Files
go-i2p/lib/crypto/aes.go

142 lines
3.8 KiB
Go
Raw Normal View History

2016-01-28 10:16:26 -05:00
package crypto
2024-10-04 22:36:32 -04:00
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
2024-10-22 17:37:17 -04:00
2024-10-18 15:10:16 -04:00
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
2024-10-04 22:36:32 -04:00
)
2024-10-18 15:10:16 -04:00
var log = logger.GetLogger()
2024-10-06 10:45:26 -04:00
// AESSymmetricKey represents a symmetric key for AES encryption/decryption
type AESSymmetricKey struct {
Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
IV []byte // Initialization Vector (must be 16 bytes for AES)
}
2024-10-06 10:45:26 -04:00
// AESSymmetricEncrypter implements the Encrypter interface using AES
type AESSymmetricEncrypter struct {
Key []byte
IV []byte
}
// Encrypt encrypts data using AES-CBC with PKCS#7 padding
2024-10-06 10:45:26 -04:00
func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error) {
2024-10-18 15:10:16 -04:00
log.WithField("data_length", len(data)).Debug("Encrypting data")
block, err := aes.NewCipher(e.Key)
2024-10-04 22:36:32 -04:00
if err != nil {
2024-10-18 15:10:16 -04:00
log.WithError(err).Error("Failed to create AES cipher")
2024-10-04 22:36:32 -04:00
return nil, err
}
plaintext := pkcs7Pad(data, aes.BlockSize)
2024-10-04 22:36:32 -04:00
ciphertext := make([]byte, len(plaintext))
mode := cipher.NewCBCEncrypter(block, e.IV)
2024-10-04 22:36:32 -04:00
mode.CryptBlocks(ciphertext, plaintext)
2024-10-18 15:10:16 -04:00
log.WithField("ciphertext_length", len(ciphertext)).Debug("Data encrypted successfully")
2024-10-04 22:36:32 -04:00
return ciphertext, nil
}
2024-10-06 10:45:26 -04:00
// AESSymmetricDecrypter implements the Decrypter interface using AES
type AESSymmetricDecrypter struct {
Key []byte
IV []byte
}
// Decrypt decrypts data using AES-CBC with PKCS#7 padding
2024-10-06 10:45:26 -04:00
func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error) {
2024-10-18 15:10:16 -04:00
log.WithField("data_length", len(data)).Debug("Decrypting data")
block, err := aes.NewCipher(d.Key)
2024-10-04 22:36:32 -04:00
if err != nil {
2024-10-18 15:10:16 -04:00
log.WithError(err).Error("Failed to create AES cipher")
2024-10-04 22:36:32 -04:00
return nil, err
}
if len(data)%aes.BlockSize != 0 {
2024-10-18 15:10:16 -04:00
log.Error("Ciphertext is not a multiple of the block size")
2024-10-04 22:36:32 -04:00
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
}
plaintext := make([]byte, len(data))
mode := cipher.NewCBCDecrypter(block, d.IV)
mode.CryptBlocks(plaintext, data)
2024-10-04 22:36:32 -04:00
plaintext, err = pkcs7Unpad(plaintext)
if err != nil {
2024-10-18 15:10:16 -04:00
log.WithError(err).Error("Failed to unpad plaintext")
2024-10-04 22:36:32 -04:00
return nil, err
}
2024-10-18 15:10:16 -04:00
log.WithField("plaintext_length", len(plaintext)).Debug("Data decrypted successfully")
2024-10-04 22:36:32 -04:00
return plaintext, nil
}
2024-10-06 10:45:26 -04:00
// NewEncrypter creates a new AESSymmetricEncrypter
func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error) {
2024-10-18 15:10:16 -04:00
log.Debug("Creating new AESSymmetricEncrypter")
2024-10-06 10:45:26 -04:00
return &AESSymmetricEncrypter{
Key: k.Key,
IV: k.IV,
}, nil
}
// Len returns the length of the key
2024-10-06 10:45:26 -04:00
func (k *AESSymmetricKey) Len() int {
return len(k.Key)
}
2024-10-06 10:45:26 -04:00
// NewDecrypter creates a new AESSymmetricDecrypter
func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error) {
return &AESSymmetricDecrypter{
Key: k.Key,
IV: k.IV,
}, nil
}
2024-10-04 22:36:32 -04:00
func pkcs7Pad(data []byte, blockSize int) []byte {
2024-10-18 15:10:16 -04:00
log.WithFields(logrus.Fields{
"data_length": len(data),
"block_size": blockSize,
}).Debug("Applying PKCS#7 padding")
2024-10-04 22:36:32 -04:00
padding := blockSize - (len(data) % blockSize)
padText := bytes.Repeat([]byte{byte(padding)}, padding)
2024-10-18 15:10:16 -04:00
padded := append(data, padText...)
log.WithField("padded_length", len(padded)).Debug("PKCS#7 padding applied")
2024-10-04 22:36:32 -04:00
return append(data, padText...)
}
func pkcs7Unpad(data []byte) ([]byte, error) {
2024-10-18 15:10:16 -04:00
log.WithField("data_length", len(data)).Debug("Removing PKCS#7 padding")
2024-10-04 22:36:32 -04:00
length := len(data)
if length == 0 {
2024-10-18 15:10:16 -04:00
log.Error("Data is empty")
2024-10-04 22:36:32 -04:00
return nil, fmt.Errorf("data is empty")
}
padding := int(data[length-1])
if padding == 0 || padding > aes.BlockSize {
2024-10-18 15:10:16 -04:00
log.WithField("padding", padding).Error("Invalid padding")
2024-10-04 22:36:32 -04:00
return nil, fmt.Errorf("invalid padding")
}
paddingStart := length - padding
for i := paddingStart; i < length; i++ {
if data[i] != byte(padding) {
2024-10-18 15:10:16 -04:00
log.Error("Invalid padding")
2024-10-04 22:36:32 -04:00
return nil, fmt.Errorf("invalid padding")
}
}
2024-10-18 15:10:16 -04:00
unpadded := data[:paddingStart]
log.WithField("unpadded_length", len(unpadded)).Debug("PKCS#7 padding removed")
return unpadded, nil
2024-10-04 22:36:32 -04:00
}