I've just took a look into chachapoly1305 library's source files and I found *Seal* and *Open* functions: https://cs.opensource.google/go/x/crypto/+/refs/tags/v0.14.0:chacha20poly1305/chacha20poly1305_generic.go .
You're right: the 16 bytes are a Poly1305 authentication tag and here is how it's generated: func writeWithPadding(p *poly1305.MAC, b []byte) { p.Write(b) if rem := len(b) % 16; rem != 0 { var buf [16]byte padLen := 16 - rem p.Write(buf[:padLen]) } } func writeUint64(p *poly1305.MAC, n int) { var buf [8]byte binary.LittleEndian.PutUint64(buf[:], uint64(n)) p.Write(buf[:]) } func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte { ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize) ciphertext, tag := out[:len(plaintext)], out[len(plaintext):] if alias.InexactOverlap(out, plaintext) { panic("chacha20poly1305: invalid buffer overlap") } var polyKey [32]byte s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce) s.XORKeyStream(polyKey[:], polyKey[:]) s.SetCounter(1) // set the counter to 1, skipping 32 bytes s.XORKeyStream(ciphertext, plaintext) p := poly1305.New(&polyKey) writeWithPadding(p, additionalData) writeWithPadding(p, ciphertext) writeUint64(p, len(additionalData)) writeUint64(p, len(plaintext)) p.Sum(tag[:0]) return ret } Any suggestions about how to replicate the same thing with Crypto++? On Monday, November 6, 2023 at 11:53:29 PM UTC+1 Lucas Marchetti wrote: > You're right, pics are not helpful. > I've also followed the advise about using test vectors instead of messages. > > That's a remake of what I need to implement in my application. > > *test.cpp* > > #include <cryptopp/cryptlib.h> > #include <cryptopp/chachapoly.h> > #include <cryptopp/filters.h> > #include <cryptopp/files.h> > #include <cryptopp/hex.h> > > > int main(int argc, char* argv[]) > { > using namespace CryptoPP; > > const byte pt[] = { > > 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 > }; > > const byte aad[] = { > 0x50,0x51,0x52,0x53,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7 > }; > > const byte key[] = { > > 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, > > 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f > }; > > const byte iv[] = { > 0x07,0x00,0x00,0x00, // Common > 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47 // IV > }; > > byte ct[sizeof(pt)], rt[sizeof(ct)], mac[16]; > > ChaCha20Poly1305::Encryption enc; > enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); > enc.EncryptAndAuthenticate(ct, mac, sizeof(mac), iv, sizeof(iv), aad, > sizeof(aad), (const byte*)pt, sizeof(pt)); > > std::cout << "Plain: \n"; > StringSource((const byte*)pt, sizeof(pt), true, new HexEncoder(new > FileSink(std::cout))); > std::cout << "\n" << std::endl; > > std::cout << "Cipher: \n"; > > for (int i = 0; i < sizeof(ct); ++i) { > > std::cout << (uint)ct[i] << " "; > > } > > std::cout << std::endl; > > std::cout << "\nMAC: \n"; > StringSource(mac, sizeof(mac), true, new HexEncoder(new > FileSink(std::cout))); > std::cout << "\n" << std::endl; > > ChaCha20Poly1305::Decryption dec; > dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); > dec.DecryptAndVerify(rt, mac, sizeof(mac), iv, sizeof(iv), aad, > sizeof(aad), ct, sizeof(ct)); > > std::cout << "Recover: "; > > StringSource(rt, sizeof(rt), true, new HexEncoder(new > FileSink(std::cout))); > > std::cout << std::endl; > > return 0; > } > > *test.go* > > package main > > import ( > "crypto/cipher" > > "fmt" > > "golang.org/x/crypto/chacha20poly1305" > ) > > // Encryption. > var ( > > key []byte > encryptedMsg []byte > aead cipher.AEAD > > ) > > func remove(slice []byte, s int) []byte { > return append(slice[:s], slice[s+1:]...) > } > > 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, > > ) > > // Select a random nonce, and leave capacity for the ciphertext. > nonce := make([]byte, 0) > nonce = append(nonce, 0x07,0x00,0x00,0x00, // Common > 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 = aead.Seal(nonce, nonce, msg, nil) > > fmt.Println("\nCipher:") > fmt.Println(encryptedMsg) > > } > > // Decryption. > 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 := aead.Open(nil, nonce, ciphertext, nil) > if err != nil { > panic(err) > } > > fmt.Println("\nRecover:") > fmt.Printf("%s\n", plaintext) > > } > > func main(){ > > var err error > > key = make([]byte, 0) > key = append(key, > 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, > > 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f) > > aead, err = chacha20poly1305.New(key) > if err != nil { > panic(err) > } > > EncrytionWithChaChaPoly() > > DecryptionWithChaChaPoly() > > } > > Here you are the output. > The highlighted text is the same of the Crypto++ output. > > [image: Screenshot 2023-11-06 234054.png] > > I think the 16 bytes at the end are part of the *Seal* function and > corresponds to the *additionalData *parameter as shown in the next pic. > Maybe the function still do something with a null pointer, so it will > append those bytes to the ciphertext anyway. > > [image: Screenshot 2023-11-06 234437.png] > > Looks like *Seal *is doing something like this: *Nonce *+ *Ciphertext *+ > *AdditionalData(?)* > Any ideas? > On Sunday, November 5, 2023 at 8:26:27 PM UTC+1 Jeffrey Walton wrote: > >> On Sun, Nov 5, 2023 at 4:38 AM Lucas Marchetti <lmarch...@gmail.com> >> wrote: >> >>> Sorry, seeing now that I've linked the wrong Golang library, here it is: >>> https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305 >>> >>> On Sunday, November 5, 2023 at 10:10:44 AM UTC+1 Lucas Marchetti wrote: >>> >>>> I've just made a test encrypting the string "Hello World!" with both >>>> client and server functions and these are the results. >>>> >>>> [image: Screenshot 2023-11-05 100312.png] >>>> >>>> Both green-highlighted bytes corresponds to the input string but, as >>>> you can see, there is a different padding that I'm 100% sure is the source >>>> of the problem. >>>> >>>> On Saturday, November 4, 2023 at 7:39:31 PM UTC+1 Lucas Marchetti wrote: >>>> >>>>> Good evening. >>>>> >>>>> I'm building a client-server application and I want to implement a >>>>> XChaCha20 communication over TCP after performing key exchange. >>>>> >>>>> What I'm issuing is a bad decryption output like the one shown in the >>>>> pic. >>>>> >>>>> [image: Screenshot 2023-11-04 193625.png] >>>>> >>>>> I'm currently using crypto++ 8.9 in the client-side and >>>>> https://pkg.go.dev/golang.org/x/crypto/chacha20 in the server-side. >>>>> >>>>> Is that something related to sealing or authentication implemented in >>>>> the Golang library? >>>>> >>>>> Functions that I'm using: >>>>> >>>>> [image: Screenshot 2023-11-04 193751.png] >>>>> >>>>> [image: Screenshot 2023-11-04 193832.png] >>>>> >>>>> Thanks in advance. >>>>> >>>> If you want help, then you should provide source code and post a link >> to a minimal reproducer. Pictures are not helpful. >> >> The wiki is full of little working examples. For example, < >> https://www.cryptopp.com/wiki/XChaCha20> and < >> https://www.cryptopp.com/wiki/XChaCha20Poly1305>. >> >> You should also probably start with test vectors, and then move onto >> arbitrary messages once things work with test vectors. Here are the ones >> Crypto++ uses for XChaCha: < >> https://github.com/weidai11/cryptopp/blob/master/TestVectors/chacha.txt>. >> And here are the ones for ChaCha20/Poly1305: < >> https://github.com/weidai11/cryptopp/blob/master/TestVectors/chacha20poly1305.txt#L4669 >> >. >> >> I'm just guessing, but the 16-bytes of garbage at the end of the >> [encrypted] message may be a Poly1305 authentication tag. But it is just a >> guess. The go documentation should tell you what you have. >> >> Jeff >> > -- You received this message because you are subscribed to the Google Groups "Crypto++ Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to cryptopp-users+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/cryptopp-users/455def34-d321-4f2c-a297-197b96410d72n%40googlegroups.com.