owned this note
owned this note
Published
Linked with GitHub
УКР | [ENG](https://hackmd.io/L46is8sVSI2l0ct572B6nw)
![](https://i.imgur.com/ULmPUgP.jpg)
:arrow_left: [На Головну](/Mj2ZqCVpSq6A6Jzm6ladlw)
# Приклад реалізації криптографічного перетворення мовою "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: [На Головну](/Mj2ZqCVpSq6A6Jzm6ladlw)
: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>