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.
169 lines
3.1 KiB
Go
169 lines
3.1 KiB
Go
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)]
|
|
}
|