You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
3.1 KiB
Go

package service
import (
cipher2 "crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"golang.org/x/crypto/blowfish"
"io"
)
type BaseMessage struct {
Signature string
}
func DecryptAndVerify(input []byte, key *rsa.PrivateKey, pub *rsa.PublicKey, signature []byte, v interface{}) error {
all, err := hex.DecodeString(string(input))
if err != nil {
return err
}
encPasswordAndIV := all[:512]
encBody := all[512:]
passwordAndIV, err := rsa.DecryptPKCS1v15(rand.Reader, key, encPasswordAndIV)
if err != nil {
return err
}
password := passwordAndIV[:32]
iv := passwordAndIV[32:40]
cipher, err := blowfish.NewCipher(password)
if err != nil {
return err
}
body := make([]byte, len(encBody))
dec := cipher2.NewCBCDecrypter(cipher, iv)
dec.CryptBlocks(body, encBody)
err = json.Unmarshal(Unpad(body), v)
if err != nil {
return err
}
baseReq, ok := v.(*BaseMessage)
if !ok {
return errors.New("non-base request")
}
recvSignature, err := hex.DecodeString(baseReq.Signature)
if err != nil {
return err
}
fingerprint := signature
fingerprintHashed := sha256.Sum256(fingerprint)
err = rsa.VerifyPKCS1v15(pub, 0, fingerprintHashed[:], recvSignature)
return err
}
func EncryptAndSign(v interface{}, key *rsa.PrivateKey, pub *rsa.PublicKey, signature []byte, writer io.Writer) error {
passwordAndIV := make([]byte, 40)
_, err := rand.Read(passwordAndIV)
if err != nil {
return err
}
encPasswordAndIV, err := rsa.EncryptPKCS1v15(rand.Reader, pub, passwordAndIV)
if err != nil {
return err
}
_, err = writer.Write([]byte(hex.EncodeToString(encPasswordAndIV)))
if err != nil {
return err
}
password := passwordAndIV[:32]
iv := passwordAndIV[32:]
cipher, err := blowfish.NewCipher(password)
if err != nil {
return err
}
hashedFingerpint := sha256.Sum256(signature)
plainSignature, err := rsa.SignPKCS1v15(rand.Reader, key, 0, hashedFingerpint[:])
if err != nil {
return err
}
sign, ok := v.(*BaseMessage)
if !ok {
return errors.New("given message can't be signed")
}
sign.Signature = hex.EncodeToString(plainSignature)
body, err := json.Marshal(v)
if err != nil {
return err
}
encBody := make([]byte, len(body))
enc := cipher2.NewCBCEncrypter(cipher, iv)
enc.CryptBlocks(encBody, body)
copy(encBody[len(encBody):], Pad(encBody))
writer.Write([]byte(hex.EncodeToString(encBody)))
return nil
}
func Pad(body []byte) []byte {
rest := len(body) % 8
if rest == 0 {
padLen := GetPad(body)
if padLen != 0 {
return []byte{8, 8, 8, 8, 8, 8, 8, 8}
}
return []byte{}
}
padLen := 8 - rest
pad := make([]byte, padLen)
for i := 0; i < padLen; i++ {
pad[i] = byte(padLen)
}
return pad
}
func GetPad(body []byte) int {
lastIndex := len(body) - 1
padLen := int(body[lastIndex])
if 1 < padLen && padLen < 9 {
isPadding := true
for i := 0; i < padLen; i++ {
if body[lastIndex-i] != byte(padLen) {
isPadding = false
break
}
}
if isPadding {
return padLen
}
}
return 0
}
func Unpad(body []byte) []byte {
return body[:len(body)-GetPad(body)]
}