Hi Jeff, thanks for the reply.
I've deleted the other messages cause I've found the solution by my own.
So, I've tested the whole thing with a test vector as you said and I found out, looking to Golang library's source code, that the output given to me was: Nonce + Ciphertext + MAC.
You were right: the last one was actually an authentication tag.
I decided to reimplement manually the Seal and Open functions removing the MAC generation and append.
I think I'm gonna implement it back in a bit: I prefer to go without authenticated encryption at the moment.
With a custom function I'm now able to remove the Nonce too and get the clear ciphertext that I can finally decrypt using Crypto++.
Here is the source code of the changed functions.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}
func sealGeneric(dst, nonce, plaintext []byte) []byte {
ret, out := sliceForAppend(dst, len(plaintext))
ciphertext, _ := out[:len(plaintext)], out[len(plaintext):]
var polyKey [32]byte
s, _ := chacha20.NewUnauthenticatedCipher(key[:], nonce)
s.XORKeyStream(polyKey[:], polyKey[:])
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
s.XORKeyStream(ciphertext, plaintext)
return ret
}
func openGeneric(dst, nonce, ciphertext []byte) ([]byte, error) {
var polyKey [32]byte
s, _ := chacha20.NewUnauthenticatedCipher(key[:], nonce)
s.XORKeyStream(polyKey[:], polyKey[:])
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
ret, out := sliceForAppend(dst, len(ciphertext))
s.XORKeyStream(out, ciphertext)
return ret, nil
}
That's how I call encryption and decryption:
func EncrytionWithChaChaPoly() {
msg := make([]byte, 0)
msg = append(msg,
0x4c,0x61,0x64,0x69,0x65,0x73,0x20,0x61,0x6e,0x64,0x20,0x47,0x65,0x6e,0x74,0x6c,
0x65,0x6d,0x65,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x63,0x6c,0x61,0x73,
0x73,0x20,0x6f,0x66,0x20,0x27,0x39,0x39,0x3a,0x20,0x49,0x66,0x20,0x49,0x20,0x63,
0x6f,0x75,0x6c,0x64,0x20,0x6f,0x66,0x66,0x65,0x72,0x20,0x79,0x6f,0x75,0x20,0x6f,
0x6e,0x6c,0x79,0x20,0x6f,0x6e,0x65,0x20,0x74,0x69,0x70,0x20,0x66,0x6f,0x72,0x20,
0x74,0x68,0x65,0x20,0x66,0x75,0x74,0x75,0x72,0x65,0x2c,0x20,0x73,0x75,0x6e,0x73,
0x63,0x72,0x65,0x65,0x6e,0x20,0x77,0x6f,0x75,0x6c,0x64,0x20,0x62,0x65,0x20,0x69,
0x74,0x2e,
)
nonce := make([]byte, 0)
nonce = append(nonce, 0x07,0x00,0x00,0x00,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x07,0x00,0x00,0x00,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47)
fmt.Println("Nonce:")
fmt.Println(nonce)
// Encrypt the message and append the ciphertext to the nonce.
encryptedMsg = sealGeneric(nonce, nonce, msg)
fmt.Println("\nCipher:")
fmt.Println(encryptedMsg)
fmt.Println(len(encryptedMsg))
}
func DecryptionWithChaChaPoly(){
if len(encryptedMsg) < aead.NonceSize() {
panic("ciphertext too short")
}
// Split nonce and ciphertext.
nonce, ciphertext := encryptedMsg[:aead.NonceSize()], encryptedMsg[aead.NonceSize():]
// Decrypt the message and check it wasn't tampered with.
plaintext, err := openGeneric(nil, nonce, ciphertext)
if err != nil {
panic(err)
}
fmt.Println("\nRecover:")
fmt.Printf("%s\n", plaintext)
}
Tell me if I did something wrong.
Thanks in advance.