ephermeral keypair, ratchets, shared secret and more

This commit is contained in:
Sudo-Ivan
2024-12-31 10:39:31 -06:00
parent ef613cc873
commit 59cef5e56a

View File

@@ -24,16 +24,17 @@ import (
const (
CURVE = "Curve25519"
KEYSIZE = 512 // 256*2 bits
RATCHETSIZE = 256 // bits
RATCHET_EXPIRY = 2592000 // 60*60*24*30 seconds (30 days)
TRUNCATED_HASHLENGTH = 128 // bits
NAME_HASH_LENGTH = 80 // bits
KEYSIZE = 512 // Combined length of encryption key (256) and signing key (256)
RATCHETSIZE = 256
RATCHET_EXPIRY = 2592000 // 30 days in seconds
TRUNCATED_HASHLENGTH = 128
NAME_HASH_LENGTH = 80
TOKEN_OVERHEAD = 16 // AES block size in bytes
AES128_BLOCKSIZE = 16 // bytes
HASHLENGTH = 256 // bits
SIGLENGTH = KEYSIZE // bits
// Token constants for Fernet-like spec
TOKEN_OVERHEAD = 16 // AES block size
AES128_BLOCKSIZE = 16
HASHLENGTH = 256
SIGLENGTH = KEYSIZE
)
type Identity struct {
@@ -209,61 +210,72 @@ func (i *Identity) Encrypt(plaintext []byte, ratchet []byte) ([]byte, error) {
return nil, errors.New("encryption failed: identity does not hold a public key")
}
// Generate ephemeral key pair
ephemeralKey, err := curve25519.X25519(make([]byte, 32), curve25519.Basepoint)
// Generate ephemeral keypair
ephemeralPrivKey := make([]byte, curve25519.ScalarSize)
if _, err := io.ReadFull(rand.Reader, ephemeralPrivKey); err != nil {
return nil, err
}
ephemeralPubKey, err := curve25519.X25519(ephemeralPrivKey, curve25519.Basepoint)
if err != nil {
return nil, err
}
ephemeralPubBytes := ephemeralKey
var targetPublicKey []byte
// Use ratchet key if provided, otherwise use identity public key
targetKey := i.publicKey
if ratchet != nil {
targetPublicKey = ratchet
} else {
targetPublicKey = i.publicKey
targetKey = ratchet
}
// Generate shared key
sharedKey, err := curve25519.X25519(ephemeralKey, targetPublicKey)
// Generate shared secret
sharedSecret, err := curve25519.X25519(ephemeralPrivKey, targetKey)
if err != nil {
return nil, err
}
// Derive encryption key using HKDF
derivedKey := hkdf.New(sha256.New, sharedKey, i.hash, nil)
kdf := hkdf.New(sha256.New, sharedSecret, i.GetSalt(), i.GetContext())
key := make([]byte, 32)
if _, err := io.ReadFull(derivedKey, key); err != nil {
if _, err := io.ReadFull(kdf, key); err != nil {
return nil, err
}
// Encrypt using AES-CBC
block, err := aes.NewCipher(key)
// Encrypt using AES-128-CBC with PKCS7 padding
block, err := aes.NewCipher(key[:16]) // Use AES-128
if err != nil {
return nil, err
}
// Add PKCS7 padding
padding := aes.BlockSize - len(plaintext)%aes.BlockSize
padtext := make([]byte, len(plaintext)+padding)
copy(padtext, plaintext)
for i := len(plaintext); i < len(padtext); i++ {
padtext[i] = byte(padding)
}
// Generate IV
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
// Pad plaintext
padding := aes.BlockSize - len(plaintext)%aes.BlockSize
padtext := make([]byte, len(plaintext)+padding)
copy(padtext, plaintext)
for i := len(plaintext); i < len(padtext); i++ {
padtext[i] = byte(padding)
}
// Encrypt
mode := cipher.NewCBCEncrypter(block, iv)
ciphertext := make([]byte, len(padtext))
mode.CryptBlocks(ciphertext, padtext)
// Combine ephemeral public key + IV + ciphertext
token := append(ephemeralPubBytes, iv...)
// Calculate HMAC
h := hmac.New(sha256.New, key)
h.Write(append(ephemeralPubKey, append(iv, ciphertext...)...))
mac := h.Sum(nil)
// Combine all components into final token
token := make([]byte, 0, len(ephemeralPubKey)+len(iv)+len(ciphertext)+len(mac))
token = append(token, ephemeralPubKey...)
token = append(token, iv...)
token = append(token, ciphertext...)
token = append(token, mac...)
return token, nil
}