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 <[email protected]>
>> 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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/cryptopp-users/455def34-d321-4f2c-a297-197b96410d72n%40googlegroups.com.