diff --git a/Tests/LibCrypto/CMakeLists.txt b/Tests/LibCrypto/CMakeLists.txt index 5a7bdd7bea..253ec16df0 100644 --- a/Tests/LibCrypto/CMakeLists.txt +++ b/Tests/LibCrypto/CMakeLists.txt @@ -5,6 +5,7 @@ set(TEST_SOURCES TestCurves.cpp TestHash.cpp TestHMAC.cpp + TestPoly1305.cpp TestRSA.cpp ) diff --git a/Tests/LibCrypto/TestPoly1305.cpp b/Tests/LibCrypto/TestPoly1305.cpp new file mode 100644 index 0000000000..c33c41929e --- /dev/null +++ b/Tests/LibCrypto/TestPoly1305.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2022, stelar7 + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +// https://datatracker.ietf.org/doc/html/rfc8439#appendix-A.3 +TEST_CASE(test_vector_1) +{ + u8 key[32] { 0 }; + u8 message[64] { 0 }; + u8 expected_result[16] { 0 }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 64 }); + auto result = MUST(mac.digest()); + + EXPECT(memcmp(result.data(), expected_result, 16) == 0); +} + +TEST_CASE(test_vector_2) +{ + u8 key[32] { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e + }; + + u8 message[375] { + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f + }; + + u8 expected_result[16] { + 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 375 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_3) +{ + u8 key[32] { + 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 message[375] { + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f + }; + + u8 expected_result[16] { + 0xf3, 0x47, 0x7e, 0x7c, 0xd9, 0x54, 0x17, 0xaf, 0x89, 0xa6, 0xb8, 0x79, 0x4c, 0x31, 0x0c, 0xf0 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 375 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_4) +{ + u8 key[32] { + 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, + 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 + }; + + u8 message[127] { + 0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, 0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f, + 0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20, 0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c, 0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, + 0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75, 0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e + }; + + u8 expected_result[16] { + 0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61, 0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 127 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_5) +{ + u8 key[32] { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 message[16] { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + u8 expected_result[16] { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 16 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_6) +{ + u8 key[32] { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + u8 message[16] { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 expected_result[16] { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 16 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_7) +{ + u8 key[32] { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 message[48] { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 expected_result[16] { + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 48 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_8) +{ + u8 key[32] { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 message[48] { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 + }; + + u8 expected_result[16] { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 48 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_9) +{ + u8 key[32] { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 message[16] { + 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + u8 expected_result[16] { + 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 16 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_10) +{ + u8 key[32] { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 message[64] { + 0xE3, 0x35, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0x79, 0xCD, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 expected_result[16] { + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 64 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} + +TEST_CASE(test_vector_11) +{ + u8 key[32] { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 message[48] { + 0xE3, 0x35, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x94, 0xD7, 0x50, 0x5E, 0x43, 0x79, 0xCD, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + u8 expected_result[16] { + 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + Crypto::Authentication::Poly1305 mac(ReadonlyBytes { key, 32 }); + mac.update(ReadonlyBytes { message, 48 }); + auto result = MUST(mac.digest()); + auto expected = ReadonlyBytes { expected_result, 16 }; + EXPECT_EQ(result, expected); +} diff --git a/Userland/Libraries/LibCrypto/Authentication/Poly1305.cpp b/Userland/Libraries/LibCrypto/Authentication/Poly1305.cpp new file mode 100644 index 0000000000..02ba66acb5 --- /dev/null +++ b/Userland/Libraries/LibCrypto/Authentication/Poly1305.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2022, stelar7 + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Crypto::Authentication { + +Poly1305::Poly1305(ReadonlyBytes key) +{ + for (size_t i = 0; i < 16; i += 4) { + m_state.r[i / 4] = AK::convert_between_host_and_little_endian(ByteReader::load32(key.offset(i))); + } + + // r[3], r[7], r[11], and r[15] are required to have their top four bits clear (be smaller than 16) + // r[4], r[8], and r[12] are required to have their bottom two bits clear (be divisible by 4) + m_state.r[0] &= 0x0FFFFFFF; + m_state.r[1] &= 0x0FFFFFFC; + m_state.r[2] &= 0x0FFFFFFC; + m_state.r[3] &= 0x0FFFFFFC; + + for (size_t i = 16; i < 32; i += 4) { + m_state.s[(i - 16) / 4] = AK::convert_between_host_and_little_endian(ByteReader::load32(key.offset(i))); + } +} + +void Poly1305::update(ReadonlyBytes message) +{ + size_t offset = 0; + while (offset < message.size()) { + u32 n = min(message.size() - offset, 16 - m_state.block_count); + memcpy(m_state.blocks + m_state.block_count, message.offset_pointer(offset), n); + m_state.block_count += n; + offset += n; + + if (m_state.block_count == 16) { + process_block(); + m_state.block_count = 0; + } + } +} + +void Poly1305::process_block() +{ + u32 a[5]; + u8 n = m_state.block_count; + + // Add one bit beyond the number of octets. For a 16-byte block, + // this is equivalent to adding 2^128 to the number. For the shorter + // block, it can be 2^120, 2^112, or any power of two that is evenly + // divisible by 8, all the way down to 2^8. + m_state.blocks[n++] = 0x01; + + // If the block is not 17 bytes long (the last block), pad it with zeros. + // This is meaningless if you are treating the blocks as numbers. + while (n < 17) { + m_state.blocks[n++] = 0x00; + } + + // Read the block as a little-endian number. + for (size_t i = 0; i < 16; i += 4) { + a[i / 4] = AK::convert_between_host_and_little_endian(ByteReader::load32(m_state.blocks + i)); + } + a[4] = m_state.blocks[16]; + + // Add this number to the accumulator. + m_state.a[0] += a[0]; + m_state.a[1] += a[1]; + m_state.a[2] += a[2]; + m_state.a[3] += a[3]; + m_state.a[4] += a[4]; + + // Carry + m_state.a[1] += m_state.a[0] >> 32; + m_state.a[2] += m_state.a[1] >> 32; + m_state.a[3] += m_state.a[2] >> 32; + m_state.a[4] += m_state.a[3] >> 32; + + // Only consider the least significant bits + a[0] = m_state.a[0] & 0xFFFFFFFF; + a[1] = m_state.a[1] & 0xFFFFFFFF; + a[2] = m_state.a[2] & 0xFFFFFFFF; + a[3] = m_state.a[3] & 0xFFFFFFFF; + a[4] = m_state.a[4] & 0xFFFFFFFF; + + // Multiply by r + m_state.a[0] = (u64)a[0] * m_state.r[0]; + m_state.a[1] = (u64)a[0] * m_state.r[1] + (u64)a[1] * m_state.r[0]; + m_state.a[2] = (u64)a[0] * m_state.r[2] + (u64)a[1] * m_state.r[1] + (u64)a[2] * m_state.r[0]; + m_state.a[3] = (u64)a[0] * m_state.r[3] + (u64)a[1] * m_state.r[2] + (u64)a[2] * m_state.r[1] + (u64)a[3] * m_state.r[0]; + m_state.a[4] = (u64)a[1] * m_state.r[3] + (u64)a[2] * m_state.r[2] + (u64)a[3] * m_state.r[1] + (u64)a[4] * m_state.r[0]; + m_state.a[5] = (u64)a[2] * m_state.r[3] + (u64)a[3] * m_state.r[2] + (u64)a[4] * m_state.r[1]; + m_state.a[6] = (u64)a[3] * m_state.r[3] + (u64)a[4] * m_state.r[2]; + m_state.a[7] = (u64)a[4] * m_state.r[3]; + + // Carry + m_state.a[1] += m_state.a[0] >> 32; + m_state.a[2] += m_state.a[1] >> 32; + m_state.a[3] += m_state.a[2] >> 32; + m_state.a[4] += m_state.a[3] >> 32; + m_state.a[5] += m_state.a[4] >> 32; + m_state.a[6] += m_state.a[5] >> 32; + m_state.a[7] += m_state.a[6] >> 32; + + // Save the high part of the accumulator + a[0] = m_state.a[4] & 0xFFFFFFFC; + a[1] = m_state.a[5] & 0xFFFFFFFF; + a[2] = m_state.a[6] & 0xFFFFFFFF; + a[3] = m_state.a[7] & 0xFFFFFFFF; + + // Only consider the least significant bits + m_state.a[0] &= 0xFFFFFFFF; + m_state.a[1] &= 0xFFFFFFFF; + m_state.a[2] &= 0xFFFFFFFF; + m_state.a[3] &= 0xFFFFFFFF; + m_state.a[4] &= 0x00000003; + + // Fast modular reduction (first pass) + m_state.a[0] += a[0]; + m_state.a[0] += (a[0] >> 2) | (a[1] << 30); + m_state.a[1] += a[1]; + m_state.a[1] += (a[1] >> 2) | (a[2] << 30); + m_state.a[2] += a[2]; + m_state.a[2] += (a[2] >> 2) | (a[3] << 30); + m_state.a[3] += a[3]; + m_state.a[3] += (a[3] >> 2); + + // Carry + m_state.a[1] += m_state.a[0] >> 32; + m_state.a[2] += m_state.a[1] >> 32; + m_state.a[3] += m_state.a[2] >> 32; + m_state.a[4] += m_state.a[3] >> 32; + + // Save the high part of the accumulator + a[0] = m_state.a[4] & 0xFFFFFFFC; + + // Only consider the least significant bits + m_state.a[0] &= 0xFFFFFFFF; + m_state.a[1] &= 0xFFFFFFFF; + m_state.a[2] &= 0xFFFFFFFF; + m_state.a[3] &= 0xFFFFFFFF; + m_state.a[4] &= 0x00000003; + + // Fast modular reduction (second pass) + m_state.a[0] += a[0]; + m_state.a[0] += a[0] >> 2; + + // Carry + m_state.a[1] += m_state.a[0] >> 32; + m_state.a[2] += m_state.a[1] >> 32; + m_state.a[3] += m_state.a[2] >> 32; + m_state.a[4] += m_state.a[3] >> 32; + + // Only consider the least significant bits + m_state.a[0] &= 0xFFFFFFFF; + m_state.a[1] &= 0xFFFFFFFF; + m_state.a[2] &= 0xFFFFFFFF; + m_state.a[3] &= 0xFFFFFFFF; + m_state.a[4] &= 0x00000003; +} + +ErrorOr Poly1305::digest() +{ + if (m_state.block_count != 0) + process_block(); + + u32 b[4]; + + // Save the accumulator + b[0] = m_state.a[0] & 0xFFFFFFFF; + b[1] = m_state.a[1] & 0xFFFFFFFF; + b[2] = m_state.a[2] & 0xFFFFFFFF; + b[3] = m_state.a[3] & 0xFFFFFFFF; + + // Compute a + 5 + m_state.a[0] += 5; + + // Carry + m_state.a[1] += m_state.a[0] >> 32; + m_state.a[2] += m_state.a[1] >> 32; + m_state.a[3] += m_state.a[2] >> 32; + m_state.a[4] += m_state.a[3] >> 32; + + // Select mask based on (a + 5) >= 2^130 + u32 mask = ((m_state.a[4] & 0x04) >> 2) - 1; + + // Select based on mask + m_state.a[0] = (m_state.a[0] & ~mask) | (b[0] & mask); + m_state.a[1] = (m_state.a[1] & ~mask) | (b[1] & mask); + m_state.a[2] = (m_state.a[2] & ~mask) | (b[2] & mask); + m_state.a[3] = (m_state.a[3] & ~mask) | (b[3] & mask); + + // Finally, the value of the secret key "s" is added to the accumulator, + // and the 128 least significant bits are serialized in little-endian + // order to form the tag. + m_state.a[0] += m_state.s[0]; + m_state.a[1] += m_state.s[1]; + m_state.a[2] += m_state.s[2]; + m_state.a[3] += m_state.s[3]; + + // Carry + m_state.a[1] += m_state.a[0] >> 32; + m_state.a[2] += m_state.a[1] >> 32; + m_state.a[3] += m_state.a[2] >> 32; + m_state.a[4] += m_state.a[3] >> 32; + + // Only consider the least significant bits + b[0] = m_state.a[0] & 0xFFFFFFFF; + b[1] = m_state.a[1] & 0xFFFFFFFF; + b[2] = m_state.a[2] & 0xFFFFFFFF; + b[3] = m_state.a[3] & 0xFFFFFFFF; + + ByteBuffer output = TRY(ByteBuffer::create_uninitialized(16)); + + for (auto i = 0; i < 4; i++) { + ByteReader::store(output.offset_pointer(i * 4), AK::convert_between_host_and_little_endian(b[i])); + } + + return output; +} + +} diff --git a/Userland/Libraries/LibCrypto/Authentication/Poly1305.h b/Userland/Libraries/LibCrypto/Authentication/Poly1305.h new file mode 100644 index 0000000000..b4c921dc18 --- /dev/null +++ b/Userland/Libraries/LibCrypto/Authentication/Poly1305.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, stelar7 + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Crypto::Authentication { + +struct State { + u32 r[4] {}; + u32 s[4] {}; + u64 a[8] {}; + u8 blocks[17] {}; + u8 block_count {}; +}; + +class Poly1305 { + +public: + explicit Poly1305(ReadonlyBytes key); + void update(ReadonlyBytes message); + ErrorOr digest(); + +private: + void process_block(); + + State m_state; +}; + +} diff --git a/Userland/Libraries/LibCrypto/CMakeLists.txt b/Userland/Libraries/LibCrypto/CMakeLists.txt index a7d707bf40..a62e63db81 100644 --- a/Userland/Libraries/LibCrypto/CMakeLists.txt +++ b/Userland/Libraries/LibCrypto/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES ASN1/DER.cpp ASN1/PEM.cpp Authentication/GHash.cpp + Authentication/Poly1305.cpp BigInt/Algorithms/BitwiseOperations.cpp BigInt/Algorithms/Division.cpp BigInt/Algorithms/GCD.cpp