mirror of
https://github.com/quarkslab/proxyblob
synced 2026-06-08 16:52:59 +00:00
99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
package protocol
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"io"
|
|
|
|
"golang.org/x/crypto/chacha20poly1305"
|
|
"golang.org/x/crypto/curve25519"
|
|
"golang.org/x/crypto/hkdf"
|
|
"golang.org/x/crypto/sha3"
|
|
)
|
|
|
|
// GenerateKeyPair creates a new X25519 key pair for key exchange.
|
|
// Returns a properly clamped private key and its corresponding public key.
|
|
func GenerateKeyPair() (privateKey, publicKey []byte) {
|
|
privateKey = make([]byte, curve25519.ScalarSize)
|
|
io.ReadFull(rand.Reader, privateKey)
|
|
|
|
// Clamp private key according to X25519 spec
|
|
privateKey[0] &= 248
|
|
privateKey[31] &= 127
|
|
privateKey[31] |= 64
|
|
|
|
publicKey, _ = curve25519.X25519(privateKey, curve25519.Basepoint)
|
|
return privateKey, publicKey
|
|
}
|
|
|
|
// GenerateNonce creates a random nonce for ChaCha20-Poly1305.
|
|
// Returns a cryptographically secure random nonce.
|
|
func GenerateNonce() []byte {
|
|
nonce := make([]byte, chacha20poly1305.NonceSizeX)
|
|
io.ReadFull(rand.Reader, nonce)
|
|
return nonce
|
|
}
|
|
|
|
// DeriveKey performs X25519 key exchange and HKDF key derivation.
|
|
// Returns a symmetric key and status code. Key is nil on error.
|
|
func DeriveKey(privateKey, peerPublicKey, nonce []byte) ([]byte, byte) {
|
|
// Derive shared secret using X25519
|
|
sharedSecret, err := curve25519.X25519(privateKey, peerPublicKey)
|
|
if err != nil {
|
|
return nil, ErrInvalidCrypto
|
|
}
|
|
|
|
// Derive symmetric key using HKDF-SHA3
|
|
kdf := hkdf.New(sha3.New256, sharedSecret, nonce, nil)
|
|
symmetricKey := make([]byte, chacha20poly1305.KeySize)
|
|
if _, err := io.ReadFull(kdf, symmetricKey); err != nil {
|
|
return nil, ErrInvalidCrypto
|
|
}
|
|
|
|
return symmetricKey, ErrNone
|
|
}
|
|
|
|
// Encrypt performs authenticated encryption using ChaCha20-Poly1305.
|
|
// Returns (nonce || ciphertext || tag) or nil on error.
|
|
func Encrypt(key, plaintext []byte) ([]byte, byte) {
|
|
aead, err := chacha20poly1305.NewX(key)
|
|
if err != nil {
|
|
return nil, ErrInvalidCrypto
|
|
}
|
|
|
|
nonce := GenerateNonce()
|
|
ciphertext := aead.Seal(nonce, nonce, plaintext, nil)
|
|
return ciphertext, ErrNone
|
|
}
|
|
|
|
// Decrypt performs authenticated decryption using ChaCha20-Poly1305.
|
|
// Returns decrypted plaintext or nil if authentication fails.
|
|
func Decrypt(key, ciphertext []byte) ([]byte, byte) {
|
|
aead, err := chacha20poly1305.NewX(key)
|
|
if err != nil {
|
|
return nil, ErrInvalidCrypto
|
|
}
|
|
|
|
if len(ciphertext) < chacha20poly1305.NonceSizeX {
|
|
return nil, ErrInvalidCrypto
|
|
}
|
|
|
|
nonce := ciphertext[:chacha20poly1305.NonceSizeX]
|
|
ciphertextBody := ciphertext[chacha20poly1305.NonceSizeX:]
|
|
|
|
plaintext, err := aead.Open(nil, nonce, ciphertextBody, nil)
|
|
if err != nil {
|
|
return nil, ErrInvalidCrypto
|
|
}
|
|
|
|
return plaintext, ErrNone
|
|
}
|
|
|
|
// Xor performs byte-wise XOR of data with a repeating key.
|
|
// Warning: This is NOT cryptographically secure, use only for basic obfuscation.
|
|
func Xor(data []byte, key []byte) []byte {
|
|
for i := range data {
|
|
data[i] ^= key[i%len(key)]
|
|
}
|
|
return data
|
|
}
|