package service import ( "crypto" cipher2 "crypto/cipher" "crypto/rand" "crypto/rsa" "crypto/sha256" "encoding/hex" "encoding/json" "golang.org/x/crypto/blowfish" "io" ) type BaseMessage struct { Signature string `json:"signature"` } func (it *BaseMessage) GetSignature() string { return it.Signature } func (it *BaseMessage) SetSignature(sig string) { it.Signature = sig } type Message interface { SetSignature(sig string) GetSignature() string } func DecryptAndVerify(input []byte, key *rsa.PrivateKey, pub *rsa.PublicKey, signature []byte, v Message) 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 } recvSignature, err := hex.DecodeString(v.GetSignature()) if err != nil { return err } fingerprint := signature fingerprintHashed := sha256.Sum256(fingerprint) err = rsa.VerifyPKCS1v15(pub, crypto.SHA256, fingerprintHashed[:], recvSignature) return err } func EncryptAndSign(v Message, 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, crypto.SHA256, hashedFingerpint[:]) if err != nil { return err } v.SetSignature(hex.EncodeToString(plainSignature)) body, err := json.Marshal(v) if err != nil { return err } enc := cipher2.NewCBCEncrypter(cipher, iv) body = append(body, Pad(body)...) encBody := make([]byte, len(body)) enc.CryptBlocks(encBody, body) 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)] }