first commit
commit
111fc341a6
|
@ -0,0 +1,96 @@
|
||||||
|
package shttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AESKey generates a random 32 byte AES Key
|
||||||
|
func AESKey() string {
|
||||||
|
bytes := make([]byte, 32) //generate a random 32 byte key for AES-256
|
||||||
|
if _, err := rand.Read(bytes); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptAESByte use system dynamic key if keyString = ""
|
||||||
|
func EncryptAESByte(ByteToEncrypt []byte, keyString string) ([]byte, error) {
|
||||||
|
if keyString == "" {
|
||||||
|
keyString = AESKey()
|
||||||
|
}
|
||||||
|
//Since the key is in string, we need to convert decode it to bytes
|
||||||
|
key, _ := hex.DecodeString(keyString)
|
||||||
|
|
||||||
|
//Create a new Cipher Block from the key
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a new GCM
|
||||||
|
aesGCM, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a nonce. Nonce should be from GCM
|
||||||
|
nonce := make([]byte, aesGCM.NonceSize())
|
||||||
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Encrypt the data using aesGCM.Seal
|
||||||
|
//Since we don't want to save the nonce somewhere else in this case, we add it as a prefix to the encrypted data. The first nonce argument in Seal is the prefix.
|
||||||
|
return aesGCM.Seal(nonce, nonce, ByteToEncrypt, nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncryptAES(stringToEncrypt string, keyString string) (string, error) {
|
||||||
|
ciphertext, err := EncryptAESByte([]byte(stringToEncrypt), keyString)
|
||||||
|
return hex.EncodeToString(ciphertext), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptAESByte use system dynamic key if keyString = ""
|
||||||
|
func DecryptAESByte(encrypted []byte, keyString string) ([]byte, error) {
|
||||||
|
if keyString == "" {
|
||||||
|
keyString = AESKey()
|
||||||
|
}
|
||||||
|
key, _ := hex.DecodeString(keyString)
|
||||||
|
|
||||||
|
//Create a new Cipher Block from the key
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a new GCM
|
||||||
|
aesGCM, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the nonce size
|
||||||
|
nonceSize := aesGCM.NonceSize()
|
||||||
|
|
||||||
|
//Extract the nonce from the encrypted data
|
||||||
|
nonce, ciphertext := encrypted[:nonceSize], encrypted[nonceSize:]
|
||||||
|
|
||||||
|
//Decrypt the data
|
||||||
|
return aesGCM.Open(nil, nonce, ciphertext, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecryptAES(encryptedString string, keyString string) (string, error) {
|
||||||
|
encrypted, err := hex.DecodeString(encryptedString)
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
decrypted, err := DecryptAESByte(encrypted, keyString)
|
||||||
|
return string(decrypted), err
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"shttp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
rk := &shttp.RSA{}
|
||||||
|
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
path := filepath.Join(home, ".ssh", "id_rsa")
|
||||||
|
file, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
pub := string(file)
|
||||||
|
if err := rk.LoadPrivate(pub); err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rk.LoadPublic("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDO1y6CLE3ZoPEy24ird1izypdVN0VEIcQiVeqZY3IOe2rQWzMG3+UJzmPj2wKFoSDxcVQxuuGe2MMX4xFCl1ChCEt85xfGrUWWAGX2IV83+UMtTS5dXLcSATs5NBhFQLgDSGBCDioSxkzBayz4IUkRihRPhd/rDSnlGITBbO6+dAtCdqIfLg/Ai7fvE2PMOcxZO7OLcZYHVkYbUn/n/DuIQbqAi2XTLWf9Z3zpKnBkqIa1RZVnQpkEO5IDj2F1X6edbDf8ScdsQwYfpBYwpQJfjLWJnRqhKy1iO9VpGoPPipiL9fJA7dA1LWlzQadaMT0/7GngFn/eFdyGvxR4zIgo4IZBzvHTjcFgaCkeVe3TOQXCVp7LwAxZc+OBzqEsuF5sjak+NE8zRjonzi3kItaG2Ldd8PonOokR45D0Vmm26fTSCPAz8exix7xm6RxZ11Y5RHrFTblQ/U/T71dxCwOgVbWbnpddm5O6Uzc5wk+BvPyscgbjJgybiXQ+kKvmiMk= AzureAD+YiFanChen@LAPTOP-SCQSNETG")
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
http.HandleFunc("/con", func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
aes := shttp.AESKey()
|
||||||
|
aesc, _ := rk.Encrypt(aes)
|
||||||
|
rw.Header().Set("aesc", aesc)
|
||||||
|
|
||||||
|
body, _ := shttp.EncryptAESByte([]byte(rk.PublicKey()), aes)
|
||||||
|
rw.Write(body)
|
||||||
|
})
|
||||||
|
http.HandleFunc("/report", func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
aesc := r.Header.Get("aesc")
|
||||||
|
aes, err := rk.Decrypt(aesc)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
datab, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
datar, err := shttp.DecryptAESByte(datab, aes)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
data := map[string]interface{}{}
|
||||||
|
json.Unmarshal(datar, &data)
|
||||||
|
fmt.Println(data)
|
||||||
|
rw.Write([]byte("ok"))
|
||||||
|
})
|
||||||
|
err = http.ListenAndServe("localhost:8080", nil)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
func() {
|
||||||
|
time.Sleep(time.Second * 10)
|
||||||
|
lk := &shttp.RSA{}
|
||||||
|
func() {
|
||||||
|
r, err := http.Get("http://localhost:8080/con")
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
aesc := r.Header.Get("aesc")
|
||||||
|
aes, err := rk.Decrypt(aesc)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
datab, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
datar, err := shttp.DecryptAESByte(datab, aes)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
if err = lk.LoadPublic(string(datar)); err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
func() {
|
||||||
|
data := map[string]interface{}{"msg": "cool"}
|
||||||
|
obj, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
aes := shttp.AESKey()
|
||||||
|
body, err := shttp.EncryptAESByte(obj, aes)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
aesc, err := lk.Encrypt(aes)
|
||||||
|
if err != nil {
|
||||||
|
Fatal(err)
|
||||||
|
}
|
||||||
|
req, _ := http.NewRequest("POST", "http://localhost:8080/report", bytes.NewReader(body))
|
||||||
|
req.Header.Set("aesc", aesc)
|
||||||
|
http.DefaultClient.Do(req)
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}()
|
||||||
|
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatal(i ...interface{}) {
|
||||||
|
_, _, line, _ := runtime.Caller(1)
|
||||||
|
prt := []interface{}{line, ": "}
|
||||||
|
fmt.Println(append(prt, i)...)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
module shttp
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
|
@ -0,0 +1,10 @@
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
@ -0,0 +1,144 @@
|
||||||
|
package shttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RSA struct {
|
||||||
|
bits int
|
||||||
|
key *rsa.PrivateKey
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) SetBits(b int) {
|
||||||
|
r.bits = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) New() (err error) {
|
||||||
|
if r.bits < 1024 || r.bits > 4096 {
|
||||||
|
r.bits = 2048
|
||||||
|
}
|
||||||
|
r.key, err = rsa.GenerateKey(rand.Reader, r.bits)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) Key() *rsa.PrivateKey {
|
||||||
|
return r.key
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) PublicKey() string {
|
||||||
|
if r.key == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(&r.key.PublicKey)}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) PrivateKey() string {
|
||||||
|
if r.key == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(r.key)}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) EncryptByte(msg []byte) ([]byte, error) {
|
||||||
|
if r.key == nil {
|
||||||
|
return nil, fmt.Errorf("no key found")
|
||||||
|
}
|
||||||
|
b, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &r.key.PublicKey, msg, []byte(""))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) Encrypt(msg string) (string, error) {
|
||||||
|
b, err := r.EncryptByte([]byte(msg))
|
||||||
|
return hex.EncodeToString(b), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) DecryptByte(msg []byte) ([]byte, error) {
|
||||||
|
if r.key == nil {
|
||||||
|
return nil, fmt.Errorf("no key found")
|
||||||
|
}
|
||||||
|
b, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, r.key, msg, []byte(""))
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) Decrypt(cypher string) (string, error) {
|
||||||
|
block, err := hex.DecodeString(cypher)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
msg, err := r.DecryptByte(block)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(msg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) LoadPublic(pub string) error {
|
||||||
|
if r.key == nil {
|
||||||
|
r.key = &rsa.PrivateKey{}
|
||||||
|
}
|
||||||
|
parsed, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(pub))
|
||||||
|
if err != nil {
|
||||||
|
block, rest := pem.Decode([]byte(pub))
|
||||||
|
if block == nil || block.Type != "RSA PUBLIC KEY" {
|
||||||
|
return fmt.Errorf("ssh: no key found")
|
||||||
|
}
|
||||||
|
if len(rest) != 0 {
|
||||||
|
r.Comment = string(rest)
|
||||||
|
}
|
||||||
|
p, err := x509.ParsePKCS1PublicKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.key.PublicKey = *p
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
parsedCryptoKey := parsed.(ssh.CryptoPublicKey)
|
||||||
|
pubCrypto := parsedCryptoKey.CryptoPublicKey()
|
||||||
|
p := pubCrypto.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
r.key.PublicKey = *p
|
||||||
|
r.Comment = comment
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) LoadPrivate(pri string) error {
|
||||||
|
var p *rsa.PrivateKey
|
||||||
|
var err error
|
||||||
|
opssh, err := ssh.ParseRawPrivateKey([]byte(pri))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p = opssh.(*rsa.PrivateKey)
|
||||||
|
if r.key != nil {
|
||||||
|
p.PublicKey = r.key.PublicKey
|
||||||
|
}
|
||||||
|
r.key = p
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RSA) LoadPrivateWithPassphrase(pri, passphrase string) error {
|
||||||
|
var p *rsa.PrivateKey
|
||||||
|
var err error
|
||||||
|
opssh, err := ssh.ParseRawPrivateKeyWithPassphrase([]byte(pri), []byte(passphrase))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p = opssh.(*rsa.PrivateKey)
|
||||||
|
if r.key != nil {
|
||||||
|
p.PublicKey = r.key.PublicKey
|
||||||
|
}
|
||||||
|
r.key = p
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue