УКР | [ENG](https://hackmd.io/L46is8sVSI2l0ct572B6nw) ![](https://i.imgur.com/ULmPUgP.jpg) # Приклад реалізації криптографічного перетворення мовою "Go" ~~~md package main import ( "bytes" "crypto" "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "fmt" "hash" "io" "log" "os" ) var ( private *rsa.PrivateKey public *rsa.PublicKey partner *rsa.PublicKey err error pssHash hash.Hash newHash = crypto.SHA256 text = "some test text" data string keyAES string sign string ) func main() { pssHash = newHash.New() private, err = readPrivKeyFile() if err != nil { return } public = &private.PublicKey partner, err = readPartnerKey() if err != nil { return } log.Println("\n\n1 - crypt\n2 - sign\n3 - verify sign\n4 - decrypt\n9 - exit") var todo int for { fmt.Scanln(&todo) switch todo { case 1: encrypt() case 2: makeSign() case 3: signVerify() case 4: decrypt() case 9: return default: log.Println("\n\n1 - crypt\n2 - sign\n3 - verify sign\n4 - decrypt\n9 - exit") } } } // BEGIN of general functions func encrypt() { n := []byte(text) aesKey, err := generateKeyAES() if err != nil { log.Println(err.Error()) return } log.Println("keyAES", aesKey) data, err = encryptAES(aesKey, n) var encryptedKeyAES []byte encryptedKeyAES, err = encryptRSA(aesKey, partner) if err != nil { log.Println(err.Error()) return } keyAES = base64.StdEncoding.EncodeToString(encryptedKeyAES) log.Println("data:", data) log.Println("keyAES:", keyAES) } func makeSign() { log.Println("makeSign") in, err := base64.StdEncoding.DecodeString(keyAES) if err != nil { log.Println("decode keyAES error", err.Error()) return } pssHash.Write(in) hashed := pssHash.Sum(nil) //PKCS out, err := rsa.SignPKCS1v15(rand.Reader, private, newHash, hashed) //OAEP //out, err := rsa.SignPSS(rand.Reader, k, newHash, hashed, nil) if err != nil { log.Println("makeSign err:", err.Error()) return } pssHash.Reset() sign = base64.StdEncoding.EncodeToString(out) log.Println("sign:", sign) } func signVerify() { in, err := base64.StdEncoding.DecodeString(keyAES) if err != nil { log.Println("decode keyAES error", err.Error()) return } signIn, err := base64.StdEncoding.DecodeString(sign) if err != nil { log.Println("decode sign error:", err.Error()) return } pssHash.Write(in) hashed := pssHash.Sum(nil) //PKCS err = rsa.VerifyPKCS1v15(partner, newHash, hashed, signIn) //OAEP //err := rsa.VerifyPSS(k, newHash, hashed, sign, nil) if err != nil { log.Println("verify sign: FAIL!") pssHash.Reset() return } pssHash.Reset() log.Println("verify sign: OK!") } func decrypt() { key, err := base64.StdEncoding.DecodeString(keyAES) if err != nil { log.Println("decode keyAES error", err.Error()) return } aesKey, err := decryptRSA(key, private) if err != nil { log.Println(err.Error()) return } decodedData, err := decryptAES(aesKey, data) log.Println("decoded:", decodedData) } //END of general functions // reading own private key func readPrivKeyFile() (*rsa.PrivateKey, error) { n, err := os.ReadFile("private.key") if err != nil { log.Println("read pubFile err:", err.Error()) return nil, err } block, _ := pem.Decode(n) key, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { log.Println("parse err:", err.Error()) return nil, err } return key, nil } // reading partner's public key func readPartnerKey() (*rsa.PublicKey, error) { var key *rsa.PublicKey n, err := os.ReadFile("partner.key") if err != nil { log.Println("read pubFile err:", err.Error()) return key, err } pemBlock, _ := pem.Decode(n) if pemBlock == nil { log.Println("pemBlock decode err") return key, fmt.Errorf("pemBlock decode err") } keyInt, err := x509.ParsePKIXPublicKey(pemBlock.Bytes) if err != nil { log.Println("ParsePKIXPublicKey err:", err.Error()) return key, err } key = keyInt.(*rsa.PublicKey) return key, nil } // AES crypto functions // encryptAES encrypts text using AES/CBC with the provided key func encryptAES(key, text []byte) (string, error) { block, err := aes.NewCipher(key) if err != nil { log.Println(err.Error()) return "", err } //text padding padedText := pad(text) ciphertext := make([]byte, aes.BlockSize+len(padedText)) iv := ciphertext[:aes.BlockSize] _, err = io.ReadFull(rand.Reader, iv) if err != nil { log.Println(err.Error()) return "", err } log.Println("encryptAES: IV =", iv) cbc := cipher.NewCBCEncrypter(block, iv) cbc.CryptBlocks(ciphertext[aes.BlockSize:], []byte(padedText)) finalMsg := base64.StdEncoding.EncodeToString(ciphertext) return finalMsg, nil } // decryptAES decrypts text using AES/CBC with the provided key func decryptAES(key []byte, text string) (string, error) { block, err := aes.NewCipher(key) if err != nil { log.Println(err.Error()) return "", err } decodedMsg, err := base64.StdEncoding.DecodeString(text) if err != nil { log.Println(err.Error()) return "", err } iv := decodedMsg[:aes.BlockSize] log.Println("decryptAES: IV =", iv) msg := decodedMsg[aes.BlockSize:] cbc := cipher.NewCBCDecrypter(block, iv) cbc.CryptBlocks(msg, msg) log.Println("padedText", string(msg)) //text unpadding unpadedText, err := unpad(msg) if err != nil { log.Println(err.Error()) return "", err } return string(unpadedText), nil } // encryptAES encrypts text using AES/GCM with the provided key func encryptAESGCM(key []byte, text string) (string, error) { const nonceSize = 12 // AES-GCM standard nonce size // Create a new AES cipher block block, err := aes.NewCipher(key) if err != nil { return "", fmt.Errorf("failed to create cipher: %w", err) } // Use GCM mode with the AES cipher gcm, err := cipher.NewGCM(block) if err != nil { return "", fmt.Errorf("failed to create GCM: %w", err) } // Generate a nonce with the required size for GCM nonce := make([]byte, nonceSize) // AES-GCM standard nonce size if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", fmt.Errorf("failed to generate nonce: %w", err) } // Encrypt and add the authentication tag using Seal ciphertext := gcm.Seal(nil, nonce, []byte(text), nil) // Prepend the nonce to the ciphertext (this is typically done for AES-GCM) finalMessage := append(nonce, ciphertext...) // Encode the final message in Base64 for easier handling return base64.StdEncoding.EncodeToString(finalMessage), nil } // decryptAESGCM decrypts text using AES-GCM with the provided key func decryptAESGCM(key []byte, text string) (string, error) { const nonceSize = 12 // AES-GCM standard nonce size // Create a new AES cipher block block, err := aes.NewCipher(key) if err != nil { return "", err } // Decode the Base64-encoded ciphertext data, err := base64.StdEncoding.DecodeString(text) if err != nil { return "", err } // Check if the ciphertext is valid and minimum contains the nonce if len(data) < nonceSize { // GCM Nonce size is typically 12 bytes return "", errors.New("ciphertext too short") } // Split the ciphertext into nonce and ciphertext nonce, ciphertext := data[:nonceSize], data[nonceSize:] // GCM Nonce size is typically 12 bytes // Use GCM mode with the AES cipher aesgcm, err := cipher.NewGCM(block) if err != nil { return "", err } // Decrypt and verify plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) if err != nil { return "", err } return string(plaintext), nil } // AES utility functions func generateKeyAES() ([]byte, error) { key := make([]byte, 16) //RSA crypto functions PKCS _, err := rand.Read(key) if err != nil { log.Println(err.Error()) return nil, err } return key, err } func pad(src []byte) []byte { padding := aes.BlockSize - len(src)%aes.BlockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(src, padtext...) } func unpad(src []byte) ([]byte, error) { length := len(src) unpadding := int(src[length-1]) if unpadding > length { return nil, errors.New("unpad error. This could happen when incorrect encryption key is used") } return src[:(length - unpadding)], nil } // RSA crypto functions PKCS 1.5 func encryptRSA(in []byte, k *rsa.PublicKey) ([]byte, error) { out, err := rsa.EncryptPKCS1v15(rand.Reader, k, in) if err != nil { log.Println(err.Error()) return out, err } return out, nil } func decryptRSA(in []byte, k *rsa.PrivateKey) ([]byte, error) { out, err := rsa.DecryptPKCS1v15(rand.Reader, k, in) if err != nil { log.Println(err.Error()) return out, err } return out, nil } // RSA crypto functions OAEP func encryptRSAOAEP(in []byte, k *rsa.PublicKey) ([]byte, error) { out, err := rsa.EncryptOAEP(pssHash, rand.Reader, k, in, nil) if err != nil { log.Println(err.Error()) return out, err } return out, nil } func decryptRSAOAEP(in []byte, k *rsa.PrivateKey) ([]byte, error) { out, err := rsa.DecryptOAEP(pssHash, rand.Reader, k, in, nil) if err != nil { log.Println(err.Error()) return out, err } return out, nil } ~~~ ![](https://i.imgur.com/17gAyWb.png) :arrow_left: [XPAY API Зміст](/Mj2ZqCVpSq6A6Jzm6ladlw) :arrow_left: [XPASS API Зміст](https://hackmd.io/eSq3juGWQLS1wVvJZiTUAQ) :arrow_left: [Загальна інформація по підключенню (API)](https://hackmd.io/g3cItPVFStez0ql3Xj-2TA) <details> <summary>Служба підтримки XPAY</summary> </br> Телефон: +38 093 891 92 00 Email: info@xpay.com.ua Telegram: @xpaysupportbot </details>