mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:52:43 +00:00 
			
		
		
		
	LibCrypto: Move each subsection into its own namespace
This commit is contained in:
		
							parent
							
								
									96dd7c2996
								
							
						
					
					
						commit
						4f89a377a4
					
				
					 9 changed files with 3256 additions and 3228 deletions
				
			
		|  | @ -28,395 +28,399 @@ | |||
| #include <LibCrypto/Cipher/AES.h> | ||||
| 
 | ||||
| namespace Crypto { | ||||
| namespace Cipher { | ||||
| 
 | ||||
| template <typename T> | ||||
| constexpr u32 get_key(T pt) | ||||
| { | ||||
|     return ((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]); | ||||
| } | ||||
| 
 | ||||
| constexpr void swap_keys(u32* keys, size_t i, size_t j) | ||||
| { | ||||
|     u32 temp = keys[i]; | ||||
|     keys[i] = keys[j]; | ||||
|     keys[j] = temp; | ||||
| } | ||||
| 
 | ||||
| String AESCipherBlock::to_string() const | ||||
| { | ||||
|     StringBuilder builder; | ||||
|     for (size_t i = 0; i < BLOCK_SIZE / 8; ++i) | ||||
|         builder.appendf("%02x", m_data[i]); | ||||
|     return builder.build(); | ||||
| } | ||||
| 
 | ||||
| String AESCipherKey::to_string() const | ||||
| { | ||||
|     StringBuilder builder; | ||||
|     for (size_t i = 0; i < (rounds() + 1) * 4; ++i) | ||||
|         builder.appendf("%02x", m_rd_keys[i]); | ||||
|     return builder.build(); | ||||
| } | ||||
| 
 | ||||
| void AESCipherKey::expand_encrypt_key(const StringView& user_key, size_t bits) | ||||
| { | ||||
|     u32* round_key; | ||||
|     u32 temp; | ||||
|     size_t i { 0 }; | ||||
| 
 | ||||
|     ASSERT(!user_key.is_null()); | ||||
|     ASSERT(is_valid_key_size(bits)); | ||||
| 
 | ||||
|     round_key = round_keys(); | ||||
| 
 | ||||
|     if (bits == 128) { | ||||
|         m_rounds = 10; | ||||
|     } else if (bits == 192) { | ||||
|         m_rounds = 12; | ||||
|     } else { | ||||
|         m_rounds = 14; | ||||
|     template <typename T> | ||||
|     constexpr u32 get_key(T pt) | ||||
|     { | ||||
|         return ((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]); | ||||
|     } | ||||
| 
 | ||||
|     round_key[0] = get_key(user_key.substring_view(0, 4).characters_without_null_termination()); | ||||
|     round_key[1] = get_key(user_key.substring_view(4, 4).characters_without_null_termination()); | ||||
|     round_key[2] = get_key(user_key.substring_view(8, 4).characters_without_null_termination()); | ||||
|     round_key[3] = get_key(user_key.substring_view(12, 4).characters_without_null_termination()); | ||||
|     if (bits == 128) { | ||||
|         for (;;) { | ||||
|             temp = round_key[3]; | ||||
|             // clang-format off
 | ||||
|     constexpr void swap_keys(u32* keys, size_t i, size_t j) | ||||
|     { | ||||
|         u32 temp = keys[i]; | ||||
|         keys[i] = keys[j]; | ||||
|         keys[j] = temp; | ||||
|     } | ||||
| 
 | ||||
|     String AESCipherBlock::to_string() const | ||||
|     { | ||||
|         StringBuilder builder; | ||||
|         for (size_t i = 0; i < BLOCK_SIZE / 8; ++i) | ||||
|             builder.appendf("%02x", m_data[i]); | ||||
|         return builder.build(); | ||||
|     } | ||||
| 
 | ||||
|     String AESCipherKey::to_string() const | ||||
|     { | ||||
|         StringBuilder builder; | ||||
|         for (size_t i = 0; i < (rounds() + 1) * 4; ++i) | ||||
|             builder.appendf("%02x", m_rd_keys[i]); | ||||
|         return builder.build(); | ||||
|     } | ||||
| 
 | ||||
|     void AESCipherKey::expand_encrypt_key(const StringView& user_key, size_t bits) | ||||
|     { | ||||
|         u32* round_key; | ||||
|         u32 temp; | ||||
|         size_t i { 0 }; | ||||
| 
 | ||||
|         ASSERT(!user_key.is_null()); | ||||
|         ASSERT(is_valid_key_size(bits)); | ||||
| 
 | ||||
|         round_key = round_keys(); | ||||
| 
 | ||||
|         if (bits == 128) { | ||||
|             m_rounds = 10; | ||||
|         } else if (bits == 192) { | ||||
|             m_rounds = 12; | ||||
|         } else { | ||||
|             m_rounds = 14; | ||||
|         } | ||||
| 
 | ||||
|         round_key[0] = get_key(user_key.substring_view(0, 4).characters_without_null_termination()); | ||||
|         round_key[1] = get_key(user_key.substring_view(4, 4).characters_without_null_termination()); | ||||
|         round_key[2] = get_key(user_key.substring_view(8, 4).characters_without_null_termination()); | ||||
|         round_key[3] = get_key(user_key.substring_view(12, 4).characters_without_null_termination()); | ||||
|         if (bits == 128) { | ||||
|             for (;;) { | ||||
|                 temp = round_key[3]; | ||||
|                 // clang-format off
 | ||||
|             round_key[4] = round_key[0] ^ | ||||
|                     (Tables::Encode2[(temp >> 16) & 0xff] & 0xff000000) ^ | ||||
|                     (Tables::Encode3[(temp >>  8) & 0xff] & 0x00ff0000) ^ | ||||
|                     (Tables::Encode0[(temp      ) & 0xff] & 0x0000ff00) ^ | ||||
|                     (Tables::Encode1[(temp >> 24)       ] & 0x000000ff) ^ Tables::RCON[i]; | ||||
|             // clang-format on
 | ||||
|             round_key[5] = round_key[1] ^ round_key[4]; | ||||
|             round_key[6] = round_key[2] ^ round_key[5]; | ||||
|             round_key[7] = round_key[3] ^ round_key[6]; | ||||
|             ++i; | ||||
|             if (i == 10) | ||||
|                 break; | ||||
|             round_key += 4; | ||||
|                     (AESTables::Encode2[(temp >> 16) & 0xff] & 0xff000000) ^ | ||||
|                     (AESTables::Encode3[(temp >>  8) & 0xff] & 0x00ff0000) ^ | ||||
|                     (AESTables::Encode0[(temp      ) & 0xff] & 0x0000ff00) ^ | ||||
|                     (AESTables::Encode1[(temp >> 24)       ] & 0x000000ff) ^ AESTables::RCON[i]; | ||||
|                 // clang-format on
 | ||||
|                 round_key[5] = round_key[1] ^ round_key[4]; | ||||
|                 round_key[6] = round_key[2] ^ round_key[5]; | ||||
|                 round_key[7] = round_key[3] ^ round_key[6]; | ||||
|                 ++i; | ||||
|                 if (i == 10) | ||||
|                     break; | ||||
|                 round_key += 4; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     round_key[4] = get_key(user_key.substring_view(16, 4).characters_without_null_termination()); | ||||
|     round_key[5] = get_key(user_key.substring_view(20, 4).characters_without_null_termination()); | ||||
|     if (bits == 192) { | ||||
|         for (;;) { | ||||
|             temp = round_key[5]; | ||||
|             // clang-format off
 | ||||
|         round_key[4] = get_key(user_key.substring_view(16, 4).characters_without_null_termination()); | ||||
|         round_key[5] = get_key(user_key.substring_view(20, 4).characters_without_null_termination()); | ||||
|         if (bits == 192) { | ||||
|             for (;;) { | ||||
|                 temp = round_key[5]; | ||||
|                 // clang-format off
 | ||||
|             round_key[6] = round_key[0] ^ | ||||
|                     (Tables::Encode2[(temp >> 16) & 0xff] & 0xff000000) ^ | ||||
|                     (Tables::Encode3[(temp >>  8) & 0xff] & 0x00ff0000) ^ | ||||
|                     (Tables::Encode0[(temp      ) & 0xff] & 0x0000ff00) ^ | ||||
|                     (Tables::Encode1[(temp >> 24)       ] & 0x000000ff) ^ Tables::RCON[i]; | ||||
|             // clang-format on
 | ||||
|             round_key[7] = round_key[1] ^ round_key[6]; | ||||
|             round_key[8] = round_key[2] ^ round_key[7]; | ||||
|             round_key[9] = round_key[3] ^ round_key[8]; | ||||
|                     (AESTables::Encode2[(temp >> 16) & 0xff] & 0xff000000) ^ | ||||
|                     (AESTables::Encode3[(temp >>  8) & 0xff] & 0x00ff0000) ^ | ||||
|                     (AESTables::Encode0[(temp      ) & 0xff] & 0x0000ff00) ^ | ||||
|                     (AESTables::Encode1[(temp >> 24)       ] & 0x000000ff) ^ AESTables::RCON[i]; | ||||
|                 // clang-format on
 | ||||
|                 round_key[7] = round_key[1] ^ round_key[6]; | ||||
|                 round_key[8] = round_key[2] ^ round_key[7]; | ||||
|                 round_key[9] = round_key[3] ^ round_key[8]; | ||||
| 
 | ||||
|             ++i; | ||||
|             if (i == 8) | ||||
|                 break; | ||||
|                 ++i; | ||||
|                 if (i == 8) | ||||
|                     break; | ||||
| 
 | ||||
|             round_key[10] = round_key[4] ^ round_key[9]; | ||||
|             round_key[11] = round_key[5] ^ round_key[10]; | ||||
|                 round_key[10] = round_key[4] ^ round_key[9]; | ||||
|                 round_key[11] = round_key[5] ^ round_key[10]; | ||||
| 
 | ||||
|             round_key += 6; | ||||
|                 round_key += 6; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     round_key[6] = get_key(user_key.substring_view(24, 4).characters_without_null_termination()); | ||||
|     round_key[7] = get_key(user_key.substring_view(28, 4).characters_without_null_termination()); | ||||
|     if (true) { // bits == 256
 | ||||
|         for (;;) { | ||||
|             temp = round_key[7]; | ||||
|             // clang-format off
 | ||||
|         round_key[6] = get_key(user_key.substring_view(24, 4).characters_without_null_termination()); | ||||
|         round_key[7] = get_key(user_key.substring_view(28, 4).characters_without_null_termination()); | ||||
|         if (true) { // bits == 256
 | ||||
|             for (;;) { | ||||
|                 temp = round_key[7]; | ||||
|                 // clang-format off
 | ||||
|             round_key[8] = round_key[0] ^ | ||||
|                     (Tables::Encode2[(temp >> 16) & 0xff] & 0xff000000) ^ | ||||
|                     (Tables::Encode3[(temp >>  8) & 0xff] & 0x00ff0000) ^ | ||||
|                     (Tables::Encode0[(temp      ) & 0xff] & 0x0000ff00) ^ | ||||
|                     (Tables::Encode1[(temp >> 24)       ] & 0x000000ff) ^ Tables::RCON[i]; | ||||
|             // clang-format on
 | ||||
|             round_key[9] = round_key[1] ^ round_key[8]; | ||||
|             round_key[10] = round_key[2] ^ round_key[9]; | ||||
|             round_key[11] = round_key[3] ^ round_key[10]; | ||||
|                     (AESTables::Encode2[(temp >> 16) & 0xff] & 0xff000000) ^ | ||||
|                     (AESTables::Encode3[(temp >>  8) & 0xff] & 0x00ff0000) ^ | ||||
|                     (AESTables::Encode0[(temp      ) & 0xff] & 0x0000ff00) ^ | ||||
|                     (AESTables::Encode1[(temp >> 24)       ] & 0x000000ff) ^ AESTables::RCON[i]; | ||||
|                 // clang-format on
 | ||||
|                 round_key[9] = round_key[1] ^ round_key[8]; | ||||
|                 round_key[10] = round_key[2] ^ round_key[9]; | ||||
|                 round_key[11] = round_key[3] ^ round_key[10]; | ||||
| 
 | ||||
|                 ++i; | ||||
|                 if (i == 7) | ||||
|                     break; | ||||
| 
 | ||||
|                 temp = round_key[11]; | ||||
|                 // clang-format off
 | ||||
|             round_key[12] = round_key[4] ^ | ||||
|                     (AESTables::Encode2[(temp >> 24)       ] & 0xff000000) ^ | ||||
|                     (AESTables::Encode3[(temp >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|                     (AESTables::Encode0[(temp >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|                     (AESTables::Encode1[(temp      ) & 0xff] & 0x000000ff) ; | ||||
|                 // clang-format on
 | ||||
|                 round_key[13] = round_key[5] ^ round_key[12]; | ||||
|                 round_key[14] = round_key[6] ^ round_key[13]; | ||||
|                 round_key[15] = round_key[7] ^ round_key[14]; | ||||
| 
 | ||||
|                 round_key += 8; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void AESCipherKey::expand_decrypt_key(const StringView& user_key, size_t bits) | ||||
|     { | ||||
|         u32* round_key; | ||||
| 
 | ||||
|         expand_encrypt_key(user_key, bits); | ||||
| 
 | ||||
|         round_key = round_keys(); | ||||
| 
 | ||||
|         // reorder round keys
 | ||||
|         for (size_t i = 0, j = 4 * rounds(); i < j; i += 4, j -= 4) { | ||||
|             swap_keys(round_key, i, j); | ||||
|             swap_keys(round_key, i + 1, j + 1); | ||||
|             swap_keys(round_key, i + 2, j + 2); | ||||
|             swap_keys(round_key, i + 3, j + 3); | ||||
|         } | ||||
| 
 | ||||
|         // apply inverse mix-column to middle rounds
 | ||||
|         for (size_t i = 1; i < rounds(); ++i) { | ||||
|             round_key += 4; | ||||
|             // clang-format off
 | ||||
|         round_key[0] = | ||||
|                 AESTables::Decode0[AESTables::Encode1[(round_key[0] >> 24)       ] & 0xff] ^ | ||||
|                 AESTables::Decode1[AESTables::Encode1[(round_key[0] >> 16) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode2[AESTables::Encode1[(round_key[0] >>  8) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode3[AESTables::Encode1[(round_key[0]      ) & 0xff] & 0xff] ; | ||||
|         round_key[1] = | ||||
|                 AESTables::Decode0[AESTables::Encode1[(round_key[1] >> 24)       ] & 0xff] ^ | ||||
|                 AESTables::Decode1[AESTables::Encode1[(round_key[1] >> 16) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode2[AESTables::Encode1[(round_key[1] >>  8) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode3[AESTables::Encode1[(round_key[1]      ) & 0xff] & 0xff] ; | ||||
|         round_key[2] = | ||||
|                 AESTables::Decode0[AESTables::Encode1[(round_key[2] >> 24)       ] & 0xff] ^ | ||||
|                 AESTables::Decode1[AESTables::Encode1[(round_key[2] >> 16) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode2[AESTables::Encode1[(round_key[2] >>  8) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode3[AESTables::Encode1[(round_key[2]      ) & 0xff] & 0xff] ; | ||||
|         round_key[3] = | ||||
|                 AESTables::Decode0[AESTables::Encode1[(round_key[3] >> 24)       ] & 0xff] ^ | ||||
|                 AESTables::Decode1[AESTables::Encode1[(round_key[3] >> 16) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode2[AESTables::Encode1[(round_key[3] >>  8) & 0xff] & 0xff] ^ | ||||
|                 AESTables::Decode3[AESTables::Encode1[(round_key[3]      ) & 0xff] & 0xff] ; | ||||
|             // clang-format on
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void AESCipher::encrypt_block(const AESCipherBlock& in, AESCipherBlock& out) | ||||
|     { | ||||
|         u32 s0, s1, s2, s3, t0, t1, t2, t3; | ||||
|         size_t r { 0 }; | ||||
| 
 | ||||
|         const auto& dec_key = key(); | ||||
|         const auto* round_keys = dec_key.round_keys(); | ||||
| 
 | ||||
|         s0 = get_key(in.data().offset_pointer(0)) ^ round_keys[0]; | ||||
|         s1 = get_key(in.data().offset_pointer(4)) ^ round_keys[1]; | ||||
|         s2 = get_key(in.data().offset_pointer(8)) ^ round_keys[2]; | ||||
|         s3 = get_key(in.data().offset_pointer(12)) ^ round_keys[3]; | ||||
| 
 | ||||
|         r = dec_key.rounds() >> 1; | ||||
| 
 | ||||
|         // apply the first |r - 1| rounds
 | ||||
|         auto i { 0 }; | ||||
|         for (;;) { | ||||
|             ++i; | ||||
|             if (i == 7) | ||||
|             // clang-format off
 | ||||
|         t0 = AESTables::Encode0[(s0 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(s1 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(s2 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(s3      ) & 0xff] ^ round_keys[4]; | ||||
|         t1 = AESTables::Encode0[(s1 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(s2 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(s3 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(s0      ) & 0xff] ^ round_keys[5]; | ||||
|         t2 = AESTables::Encode0[(s2 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(s3 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(s0 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(s1      ) & 0xff] ^ round_keys[6]; | ||||
|         t3 = AESTables::Encode0[(s3 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(s0 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(s1 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(s2      ) & 0xff] ^ round_keys[7]; | ||||
|             // clang-format on
 | ||||
| 
 | ||||
|             round_keys += 8; | ||||
|             --r; | ||||
|             ++i; | ||||
|             if (r == 0) | ||||
|                 break; | ||||
| 
 | ||||
|             temp = round_key[11]; | ||||
|             // clang-format off
 | ||||
|             round_key[12] = round_key[4] ^ | ||||
|                     (Tables::Encode2[(temp >> 24)       ] & 0xff000000) ^ | ||||
|                     (Tables::Encode3[(temp >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|                     (Tables::Encode0[(temp >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|                     (Tables::Encode1[(temp      ) & 0xff] & 0x000000ff) ; | ||||
|         s0 = AESTables::Encode0[(t0 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(t1 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(t2 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(t3      ) & 0xff] ^ round_keys[0]; | ||||
|         s1 = AESTables::Encode0[(t1 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(t2 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(t3 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(t0      ) & 0xff] ^ round_keys[1]; | ||||
|         s2 = AESTables::Encode0[(t2 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(t3 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(t0 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(t1      ) & 0xff] ^ round_keys[2]; | ||||
|         s3 = AESTables::Encode0[(t3 >> 24)       ] ^ | ||||
|              AESTables::Encode1[(t0 >> 16) & 0xff] ^ | ||||
|              AESTables::Encode2[(t1 >>  8) & 0xff] ^ | ||||
|              AESTables::Encode3[(t2      ) & 0xff] ^ round_keys[3]; | ||||
|             // clang-format on
 | ||||
|             round_key[13] = round_key[5] ^ round_key[12]; | ||||
|             round_key[14] = round_key[6] ^ round_key[13]; | ||||
|             round_key[15] = round_key[7] ^ round_key[14]; | ||||
| 
 | ||||
|             round_key += 8; | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void AESCipherKey::expand_decrypt_key(const StringView& user_key, size_t bits) | ||||
| { | ||||
|     u32* round_key; | ||||
| 
 | ||||
|     expand_encrypt_key(user_key, bits); | ||||
| 
 | ||||
|     round_key = round_keys(); | ||||
| 
 | ||||
|     // reorder round keys
 | ||||
|     for (size_t i = 0, j = 4 * rounds(); i < j; i += 4, j -= 4) { | ||||
|         swap_keys(round_key, i, j); | ||||
|         swap_keys(round_key, i + 1, j + 1); | ||||
|         swap_keys(round_key, i + 2, j + 2); | ||||
|         swap_keys(round_key, i + 3, j + 3); | ||||
|     } | ||||
| 
 | ||||
|     // apply inverse mix-column to middle rounds
 | ||||
|     for (size_t i = 1; i < rounds(); ++i) { | ||||
|         round_key += 4; | ||||
|         // apply the last round and put the encrypted data into out
 | ||||
|         // clang-format off
 | ||||
|         round_key[0] = | ||||
|                 Tables::Decode0[Tables::Encode1[(round_key[0] >> 24)       ] & 0xff] ^ | ||||
|                 Tables::Decode1[Tables::Encode1[(round_key[0] >> 16) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode2[Tables::Encode1[(round_key[0] >>  8) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode3[Tables::Encode1[(round_key[0]      ) & 0xff] & 0xff] ; | ||||
|         round_key[1] = | ||||
|                 Tables::Decode0[Tables::Encode1[(round_key[1] >> 24)       ] & 0xff] ^ | ||||
|                 Tables::Decode1[Tables::Encode1[(round_key[1] >> 16) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode2[Tables::Encode1[(round_key[1] >>  8) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode3[Tables::Encode1[(round_key[1]      ) & 0xff] & 0xff] ; | ||||
|         round_key[2] = | ||||
|                 Tables::Decode0[Tables::Encode1[(round_key[2] >> 24)       ] & 0xff] ^ | ||||
|                 Tables::Decode1[Tables::Encode1[(round_key[2] >> 16) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode2[Tables::Encode1[(round_key[2] >>  8) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode3[Tables::Encode1[(round_key[2]      ) & 0xff] & 0xff] ; | ||||
|         round_key[3] = | ||||
|                 Tables::Decode0[Tables::Encode1[(round_key[3] >> 24)       ] & 0xff] ^ | ||||
|                 Tables::Decode1[Tables::Encode1[(round_key[3] >> 16) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode2[Tables::Encode1[(round_key[3] >>  8) & 0xff] & 0xff] ^ | ||||
|                 Tables::Decode3[Tables::Encode1[(round_key[3]      ) & 0xff] & 0xff] ; | ||||
|         // clang-format on
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void AESCipher::encrypt_block(const AESCipherBlock& in, AESCipherBlock& out) | ||||
| { | ||||
|     u32 s0, s1, s2, s3, t0, t1, t2, t3; | ||||
|     size_t r { 0 }; | ||||
| 
 | ||||
|     const auto& dec_key = key(); | ||||
|     const auto* round_keys = dec_key.round_keys(); | ||||
| 
 | ||||
|     s0 = get_key(in.data().offset_pointer(0)) ^ round_keys[0]; | ||||
|     s1 = get_key(in.data().offset_pointer(4)) ^ round_keys[1]; | ||||
|     s2 = get_key(in.data().offset_pointer(8)) ^ round_keys[2]; | ||||
|     s3 = get_key(in.data().offset_pointer(12)) ^ round_keys[3]; | ||||
| 
 | ||||
|     r = dec_key.rounds() >> 1; | ||||
| 
 | ||||
|     // apply the first |r - 1| rounds
 | ||||
|     auto i { 0 }; | ||||
|     for (;;) { | ||||
|         ++i; | ||||
|         // clang-format off
 | ||||
|         t0 = Tables::Encode0[(s0 >> 24)       ] ^ | ||||
|              Tables::Encode1[(s1 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(s2 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(s3      ) & 0xff] ^ round_keys[4]; | ||||
|         t1 = Tables::Encode0[(s1 >> 24)       ] ^ | ||||
|              Tables::Encode1[(s2 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(s3 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(s0      ) & 0xff] ^ round_keys[5]; | ||||
|         t2 = Tables::Encode0[(s2 >> 24)       ] ^ | ||||
|              Tables::Encode1[(s3 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(s0 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(s1      ) & 0xff] ^ round_keys[6]; | ||||
|         t3 = Tables::Encode0[(s3 >> 24)       ] ^ | ||||
|              Tables::Encode1[(s0 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(s1 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(s2      ) & 0xff] ^ round_keys[7]; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         round_keys += 8; | ||||
|         --r; | ||||
|         ++i; | ||||
|         if (r == 0) | ||||
|             break; | ||||
| 
 | ||||
|         // clang-format off
 | ||||
|         s0 = Tables::Encode0[(t0 >> 24)       ] ^ | ||||
|              Tables::Encode1[(t1 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(t2 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(t3      ) & 0xff] ^ round_keys[0]; | ||||
|         s1 = Tables::Encode0[(t1 >> 24)       ] ^ | ||||
|              Tables::Encode1[(t2 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(t3 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(t0      ) & 0xff] ^ round_keys[1]; | ||||
|         s2 = Tables::Encode0[(t2 >> 24)       ] ^ | ||||
|              Tables::Encode1[(t3 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(t0 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(t1      ) & 0xff] ^ round_keys[2]; | ||||
|         s3 = Tables::Encode0[(t3 >> 24)       ] ^ | ||||
|              Tables::Encode1[(t0 >> 16) & 0xff] ^ | ||||
|              Tables::Encode2[(t1 >>  8) & 0xff] ^ | ||||
|              Tables::Encode3[(t2      ) & 0xff] ^ round_keys[3]; | ||||
|         // clang-format on
 | ||||
|     } | ||||
| 
 | ||||
|     // apply the last round and put the encrypted data into out
 | ||||
|     // clang-format off
 | ||||
|     s0 = (Tables::Encode2[(t0 >> 24)       ] & 0xff000000) ^ | ||||
|          (Tables::Encode3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (Tables::Encode0[(t2 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (Tables::Encode1[(t3      ) & 0xff] & 0x000000ff) ^ round_keys[0]; | ||||
|     s0 = (AESTables::Encode2[(t0 >> 24)       ] & 0xff000000) ^ | ||||
|          (AESTables::Encode3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (AESTables::Encode0[(t2 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (AESTables::Encode1[(t3      ) & 0xff] & 0x000000ff) ^ round_keys[0]; | ||||
|     out.put(0, s0); | ||||
| 
 | ||||
|     s1 = (Tables::Encode2[(t1 >> 24)       ] & 0xff000000) ^ | ||||
|          (Tables::Encode3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (Tables::Encode0[(t3 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (Tables::Encode1[(t0      ) & 0xff] & 0x000000ff) ^ round_keys[1]; | ||||
|     s1 = (AESTables::Encode2[(t1 >> 24)       ] & 0xff000000) ^ | ||||
|          (AESTables::Encode3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (AESTables::Encode0[(t3 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (AESTables::Encode1[(t0      ) & 0xff] & 0x000000ff) ^ round_keys[1]; | ||||
|     out.put(4, s1); | ||||
| 
 | ||||
|     s2 = (Tables::Encode2[(t2 >> 24)       ] & 0xff000000) ^ | ||||
|          (Tables::Encode3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (Tables::Encode0[(t0 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (Tables::Encode1[(t1      ) & 0xff] & 0x000000ff) ^ round_keys[2]; | ||||
|     s2 = (AESTables::Encode2[(t2 >> 24)       ] & 0xff000000) ^ | ||||
|          (AESTables::Encode3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (AESTables::Encode0[(t0 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (AESTables::Encode1[(t1      ) & 0xff] & 0x000000ff) ^ round_keys[2]; | ||||
|     out.put(8, s2); | ||||
| 
 | ||||
|     s3 = (Tables::Encode2[(t3 >> 24)       ] & 0xff000000) ^ | ||||
|          (Tables::Encode3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (Tables::Encode0[(t1 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (Tables::Encode1[(t2      ) & 0xff] & 0x000000ff) ^ round_keys[3]; | ||||
|     s3 = (AESTables::Encode2[(t3 >> 24)       ] & 0xff000000) ^ | ||||
|          (AESTables::Encode3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ | ||||
|          (AESTables::Encode0[(t1 >>  8) & 0xff] & 0x0000ff00) ^ | ||||
|          (AESTables::Encode1[(t2      ) & 0xff] & 0x000000ff) ^ round_keys[3]; | ||||
|     out.put(12, s3); | ||||
|     // clang-format on
 | ||||
| } | ||||
| 
 | ||||
| void AESCipher::decrypt_block(const AESCipherBlock& in, AESCipherBlock& out) | ||||
| { | ||||
| 
 | ||||
|     u32 s0, s1, s2, s3, t0, t1, t2, t3; | ||||
|     size_t r { 0 }; | ||||
| 
 | ||||
|     const auto& dec_key = key(); | ||||
|     const auto* round_keys = dec_key.round_keys(); | ||||
| 
 | ||||
|     s0 = get_key(in.data().offset_pointer(0)) ^ round_keys[0]; | ||||
|     s1 = get_key(in.data().offset_pointer(4)) ^ round_keys[1]; | ||||
|     s2 = get_key(in.data().offset_pointer(8)) ^ round_keys[2]; | ||||
|     s3 = get_key(in.data().offset_pointer(12)) ^ round_keys[3]; | ||||
| 
 | ||||
|     r = dec_key.rounds() >> 1; | ||||
| 
 | ||||
|     // apply the first |r - 1| rounds
 | ||||
|     for (;;) { | ||||
|         // clang-format off
 | ||||
|         t0 = Tables::Decode0[(s0 >> 24)       ] ^ | ||||
|              Tables::Decode1[(s3 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(s2 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(s1      ) & 0xff] ^ round_keys[4]; | ||||
|         t1 = Tables::Decode0[(s1 >> 24)       ] ^ | ||||
|              Tables::Decode1[(s0 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(s3 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(s2      ) & 0xff] ^ round_keys[5]; | ||||
|         t2 = Tables::Decode0[(s2 >> 24)       ] ^ | ||||
|              Tables::Decode1[(s1 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(s0 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(s3      ) & 0xff] ^ round_keys[6]; | ||||
|         t3 = Tables::Decode0[(s3 >> 24)       ] ^ | ||||
|              Tables::Decode1[(s2 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(s1 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(s0      ) & 0xff] ^ round_keys[7]; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         round_keys += 8; | ||||
|         --r; | ||||
|         if (r == 0) | ||||
|             break; | ||||
| 
 | ||||
|         // clang-format off
 | ||||
|         s0 = Tables::Decode0[(t0 >> 24)       ] ^ | ||||
|              Tables::Decode1[(t3 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(t2 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(t1      ) & 0xff] ^ round_keys[0]; | ||||
|         s1 = Tables::Decode0[(t1 >> 24)       ] ^ | ||||
|              Tables::Decode1[(t0 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(t3 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(t2      ) & 0xff] ^ round_keys[1]; | ||||
|         s2 = Tables::Decode0[(t2 >> 24)       ] ^ | ||||
|              Tables::Decode1[(t1 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(t0 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(t3      ) & 0xff] ^ round_keys[2]; | ||||
|         s3 = Tables::Decode0[(t3 >> 24)       ] ^ | ||||
|              Tables::Decode1[(t2 >> 16) & 0xff] ^ | ||||
|              Tables::Decode2[(t1 >>  8) & 0xff] ^ | ||||
|              Tables::Decode3[(t0      ) & 0xff] ^ round_keys[3]; | ||||
|         // clang-format on
 | ||||
|     } | ||||
| 
 | ||||
|     // apply the last round and put the decrypted data into out
 | ||||
|     // clang-format off
 | ||||
|     s0 = ((u32)Tables::Decode4[(t0 >> 24)       ] << 24) ^ | ||||
|          ((u32)Tables::Decode4[(t3 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)Tables::Decode4[(t2 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)Tables::Decode4[(t1      ) & 0xff]      ) ^ round_keys[0]; | ||||
|     void AESCipher::decrypt_block(const AESCipherBlock& in, AESCipherBlock& out) | ||||
|     { | ||||
| 
 | ||||
|         u32 s0, s1, s2, s3, t0, t1, t2, t3; | ||||
|         size_t r { 0 }; | ||||
| 
 | ||||
|         const auto& dec_key = key(); | ||||
|         const auto* round_keys = dec_key.round_keys(); | ||||
| 
 | ||||
|         s0 = get_key(in.data().offset_pointer(0)) ^ round_keys[0]; | ||||
|         s1 = get_key(in.data().offset_pointer(4)) ^ round_keys[1]; | ||||
|         s2 = get_key(in.data().offset_pointer(8)) ^ round_keys[2]; | ||||
|         s3 = get_key(in.data().offset_pointer(12)) ^ round_keys[3]; | ||||
| 
 | ||||
|         r = dec_key.rounds() >> 1; | ||||
| 
 | ||||
|         // apply the first |r - 1| rounds
 | ||||
|         for (;;) { | ||||
|             // clang-format off
 | ||||
|         t0 = AESTables::Decode0[(s0 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(s3 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(s2 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(s1      ) & 0xff] ^ round_keys[4]; | ||||
|         t1 = AESTables::Decode0[(s1 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(s0 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(s3 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(s2      ) & 0xff] ^ round_keys[5]; | ||||
|         t2 = AESTables::Decode0[(s2 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(s1 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(s0 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(s3      ) & 0xff] ^ round_keys[6]; | ||||
|         t3 = AESTables::Decode0[(s3 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(s2 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(s1 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(s0      ) & 0xff] ^ round_keys[7]; | ||||
|             // clang-format on
 | ||||
| 
 | ||||
|             round_keys += 8; | ||||
|             --r; | ||||
|             if (r == 0) | ||||
|                 break; | ||||
| 
 | ||||
|             // clang-format off
 | ||||
|         s0 = AESTables::Decode0[(t0 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(t3 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(t2 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(t1      ) & 0xff] ^ round_keys[0]; | ||||
|         s1 = AESTables::Decode0[(t1 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(t0 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(t3 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(t2      ) & 0xff] ^ round_keys[1]; | ||||
|         s2 = AESTables::Decode0[(t2 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(t1 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(t0 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(t3      ) & 0xff] ^ round_keys[2]; | ||||
|         s3 = AESTables::Decode0[(t3 >> 24)       ] ^ | ||||
|              AESTables::Decode1[(t2 >> 16) & 0xff] ^ | ||||
|              AESTables::Decode2[(t1 >>  8) & 0xff] ^ | ||||
|              AESTables::Decode3[(t0      ) & 0xff] ^ round_keys[3]; | ||||
|             // clang-format on
 | ||||
|         } | ||||
| 
 | ||||
|         // apply the last round and put the decrypted data into out
 | ||||
|         // clang-format off
 | ||||
|     s0 = ((u32)AESTables::Decode4[(t0 >> 24)       ] << 24) ^ | ||||
|          ((u32)AESTables::Decode4[(t3 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)AESTables::Decode4[(t2 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)AESTables::Decode4[(t1      ) & 0xff]      ) ^ round_keys[0]; | ||||
|     out.put(0, s0); | ||||
| 
 | ||||
|     s1 = ((u32)Tables::Decode4[(t1 >> 24)       ] << 24) ^ | ||||
|          ((u32)Tables::Decode4[(t0 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)Tables::Decode4[(t3 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)Tables::Decode4[(t2      ) & 0xff]      ) ^ round_keys[1]; | ||||
|     s1 = ((u32)AESTables::Decode4[(t1 >> 24)       ] << 24) ^ | ||||
|          ((u32)AESTables::Decode4[(t0 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)AESTables::Decode4[(t3 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)AESTables::Decode4[(t2      ) & 0xff]      ) ^ round_keys[1]; | ||||
|     out.put(4, s1); | ||||
| 
 | ||||
|     s2 = ((u32)Tables::Decode4[(t2 >> 24)       ] << 24) ^ | ||||
|          ((u32)Tables::Decode4[(t1 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)Tables::Decode4[(t0 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)Tables::Decode4[(t3      ) & 0xff]      ) ^ round_keys[2]; | ||||
|     s2 = ((u32)AESTables::Decode4[(t2 >> 24)       ] << 24) ^ | ||||
|          ((u32)AESTables::Decode4[(t1 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)AESTables::Decode4[(t0 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)AESTables::Decode4[(t3      ) & 0xff]      ) ^ round_keys[2]; | ||||
|     out.put(8, s2); | ||||
| 
 | ||||
|     s3 = ((u32)Tables::Decode4[(t3 >> 24)       ] << 24) ^ | ||||
|          ((u32)Tables::Decode4[(t2 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)Tables::Decode4[(t1 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)Tables::Decode4[(t0      ) & 0xff]      ) ^ round_keys[3]; | ||||
|     s3 = ((u32)AESTables::Decode4[(t3 >> 24)       ] << 24) ^ | ||||
|          ((u32)AESTables::Decode4[(t2 >> 16) & 0xff] << 16) ^ | ||||
|          ((u32)AESTables::Decode4[(t1 >>  8) & 0xff] <<  8) ^ | ||||
|          ((u32)AESTables::Decode4[(t0      ) & 0xff]      ) ^ round_keys[3]; | ||||
|     out.put(12, s3); | ||||
|     // clang-format on
 | ||||
| } | ||||
|         // clang-format on
 | ||||
|     } | ||||
| 
 | ||||
| void AESCipherBlock::overwrite(const ByteBuffer& buffer) | ||||
| { | ||||
|     overwrite(buffer.data(), buffer.size()); | ||||
| } | ||||
|     void AESCipherBlock::overwrite(const ByteBuffer& buffer) | ||||
|     { | ||||
|         overwrite(buffer.data(), buffer.size()); | ||||
|     } | ||||
| 
 | ||||
| void AESCipherBlock::overwrite(const u8* data, size_t length) | ||||
| { | ||||
|     ASSERT(length <= m_data.size()); | ||||
|     m_data.overwrite(0, data, length); | ||||
|     if (length < m_data.size()) { | ||||
|         switch (padding_mode()) { | ||||
|         case PaddingMode::Null: | ||||
|             // fill with zeros
 | ||||
|             __builtin_memset(m_data.data() + length, 0, m_data.size() - length); | ||||
|             break; | ||||
|         case PaddingMode::CMS: | ||||
|             // fill with the length of the padding bytes
 | ||||
|             __builtin_memset(m_data.data() + length, m_data.size() - length, m_data.size() - length); | ||||
|             break; | ||||
|         default: | ||||
|             // FIXME: We should handle the rest of the common padding modes
 | ||||
|             ASSERT_NOT_REACHED(); | ||||
|     void AESCipherBlock::overwrite(const u8* data, size_t length) | ||||
|     { | ||||
|         ASSERT(length <= m_data.size()); | ||||
|         m_data.overwrite(0, data, length); | ||||
|         if (length < m_data.size()) { | ||||
|             switch (padding_mode()) { | ||||
|             case PaddingMode::Null: | ||||
|                 // fill with zeros
 | ||||
|                 __builtin_memset(m_data.data() + length, 0, m_data.size() - length); | ||||
|                 break; | ||||
|             case PaddingMode::CMS: | ||||
|                 // fill with the length of the padding bytes
 | ||||
|                 __builtin_memset(m_data.data() + length, m_data.size() - length, m_data.size() - length); | ||||
|                 break; | ||||
|             default: | ||||
|                 // FIXME: We should handle the rest of the common padding modes
 | ||||
|                 ASSERT_NOT_REACHED(); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -28,109 +28,110 @@ | |||
| 
 | ||||
| #include <AK/ByteBuffer.h> | ||||
| #include <AK/Optional.h> | ||||
| #include <AK/RefPtr.h> | ||||
| #include <AK/Types.h> | ||||
| 
 | ||||
| namespace Crypto { | ||||
| namespace Cipher { | ||||
| 
 | ||||
| enum class Intent { | ||||
|     Encryption, | ||||
|     Decryption, | ||||
| }; | ||||
|     enum class Intent { | ||||
|         Encryption, | ||||
|         Decryption, | ||||
|     }; | ||||
| 
 | ||||
| enum class PaddingMode { | ||||
|     CMS, // RFC 1423
 | ||||
|     Null, | ||||
|     // FIXME: We do not implement these yet
 | ||||
|     Bit, | ||||
|     Random, | ||||
|     Space, | ||||
|     ZeroLength, | ||||
| }; | ||||
|     enum class PaddingMode { | ||||
|         CMS, // RFC 1423
 | ||||
|         Null, | ||||
|         // FIXME: We do not implement these yet
 | ||||
|         Bit, | ||||
|         Random, | ||||
|         Space, | ||||
|         ZeroLength, | ||||
|     }; | ||||
| 
 | ||||
| template <typename B, typename T> | ||||
| class Cipher; | ||||
|     template <typename B, typename T> | ||||
|     class Cipher; | ||||
| 
 | ||||
| struct CipherBlock { | ||||
| public: | ||||
|     explicit CipherBlock(PaddingMode mode) | ||||
|         : m_padding_mode(mode) | ||||
|     { | ||||
|     } | ||||
|     struct CipherBlock { | ||||
|     public: | ||||
|         explicit CipherBlock(PaddingMode mode) | ||||
|             : m_padding_mode(mode) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|     static size_t block_size() { ASSERT_NOT_REACHED(); } | ||||
|         static size_t block_size() { ASSERT_NOT_REACHED(); } | ||||
| 
 | ||||
|     virtual ByteBuffer get() const = 0; | ||||
|     virtual const ByteBuffer& data() const = 0; | ||||
|         virtual ByteBuffer get() const = 0; | ||||
|         virtual const ByteBuffer& data() const = 0; | ||||
| 
 | ||||
|     virtual void overwrite(const ByteBuffer&) = 0; | ||||
|     virtual void overwrite(const u8*, size_t) = 0; | ||||
|         virtual void overwrite(const ByteBuffer&) = 0; | ||||
|         virtual void overwrite(const u8*, size_t) = 0; | ||||
| 
 | ||||
|     virtual void apply_initialization_vector(const u8* ivec) = 0; | ||||
|         virtual void apply_initialization_vector(const u8* ivec) = 0; | ||||
| 
 | ||||
|     PaddingMode padding_mode() const { return m_padding_mode; } | ||||
|         PaddingMode padding_mode() const { return m_padding_mode; } | ||||
| 
 | ||||
|     template <typename T> | ||||
|     void put(size_t offset, T value) | ||||
|     { | ||||
|         ASSERT(offset + sizeof(T) <= data().size()); | ||||
|         auto* ptr = data().data() + offset; | ||||
|         auto index { 0 }; | ||||
|         template <typename T> | ||||
|         void put(size_t offset, T value) | ||||
|         { | ||||
|             ASSERT(offset + sizeof(T) <= data().size()); | ||||
|             auto* ptr = data().data() + offset; | ||||
|             auto index { 0 }; | ||||
| 
 | ||||
|         ASSERT(sizeof(T) <= 4); | ||||
|             ASSERT(sizeof(T) <= 4); | ||||
| 
 | ||||
|         if constexpr (sizeof(T) > 3) | ||||
|             ptr[index++] = (u8)(value >> 24); | ||||
|             if constexpr (sizeof(T) > 3) | ||||
|                 ptr[index++] = (u8)(value >> 24); | ||||
| 
 | ||||
|         if constexpr (sizeof(T) > 2) | ||||
|             ptr[index++] = (u8)(value >> 16); | ||||
|             if constexpr (sizeof(T) > 2) | ||||
|                 ptr[index++] = (u8)(value >> 16); | ||||
| 
 | ||||
|         if constexpr (sizeof(T) > 1) | ||||
|             ptr[index++] = (u8)(value >> 8); | ||||
|             if constexpr (sizeof(T) > 1) | ||||
|                 ptr[index++] = (u8)(value >> 8); | ||||
| 
 | ||||
|         ptr[index] = (u8)value; | ||||
|     } | ||||
|             ptr[index] = (u8)value; | ||||
|         } | ||||
| 
 | ||||
| private: | ||||
|     virtual ByteBuffer& data() = 0; | ||||
|     PaddingMode m_padding_mode; | ||||
| }; | ||||
|     private: | ||||
|         virtual ByteBuffer& data() = 0; | ||||
|         PaddingMode m_padding_mode; | ||||
|     }; | ||||
| 
 | ||||
| struct CipherKey { | ||||
|     virtual ByteBuffer data() const = 0; | ||||
|     static bool is_valid_key_size(size_t) { return false; }; | ||||
|     struct CipherKey { | ||||
|         virtual ByteBuffer data() const = 0; | ||||
|         static bool is_valid_key_size(size_t) { return false; }; | ||||
| 
 | ||||
|     virtual ~CipherKey() { } | ||||
|         virtual ~CipherKey() { } | ||||
| 
 | ||||
| protected: | ||||
|     virtual void expand_encrypt_key(const ByteBuffer& user_key, size_t bits) = 0; | ||||
|     virtual void expand_decrypt_key(const ByteBuffer& user_key, size_t bits) = 0; | ||||
|     size_t bits { 0 }; | ||||
| }; | ||||
|     protected: | ||||
|         virtual void expand_encrypt_key(const ByteBuffer& user_key, size_t bits) = 0; | ||||
|         virtual void expand_decrypt_key(const ByteBuffer& user_key, size_t bits) = 0; | ||||
|         size_t bits { 0 }; | ||||
|     }; | ||||
| 
 | ||||
| template <typename KeyT = CipherKey, typename BlockT = CipherBlock> | ||||
| class Cipher { | ||||
| public: | ||||
|     using KeyType = KeyT; | ||||
|     using BlockType = BlockT; | ||||
|     template <typename KeyT = CipherKey, typename BlockT = CipherBlock> | ||||
|     class Cipher { | ||||
|     public: | ||||
|         using KeyType = KeyT; | ||||
|         using BlockType = BlockT; | ||||
| 
 | ||||
|     explicit Cipher<KeyT, BlockT>(PaddingMode mode) | ||||
|         : m_padding_mode(mode) | ||||
|     { | ||||
|     } | ||||
|         explicit Cipher<KeyT, BlockT>(PaddingMode mode) | ||||
|             : m_padding_mode(mode) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|     virtual const KeyType& key() const = 0; | ||||
|     virtual KeyType& key() = 0; | ||||
|         virtual const KeyType& key() const = 0; | ||||
|         virtual KeyType& key() = 0; | ||||
| 
 | ||||
|     static size_t block_size() { return BlockType::block_size(); } | ||||
|         static size_t block_size() { return BlockType::block_size(); } | ||||
| 
 | ||||
|     PaddingMode padding_mode() const { return m_padding_mode; } | ||||
|         PaddingMode padding_mode() const { return m_padding_mode; } | ||||
| 
 | ||||
|     virtual void encrypt_block(const BlockType& in, BlockType& out) = 0; | ||||
|     virtual void decrypt_block(const BlockType& in, BlockType& out) = 0; | ||||
|         virtual void encrypt_block(const BlockType& in, BlockType& out) = 0; | ||||
|         virtual void decrypt_block(const BlockType& in, BlockType& out) = 0; | ||||
| 
 | ||||
| private: | ||||
|     PaddingMode m_padding_mode { PaddingMode::CMS }; | ||||
| }; | ||||
|     private: | ||||
|         PaddingMode m_padding_mode; | ||||
|     }; | ||||
| } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,86 +29,89 @@ | |||
| #include <LibCrypto/Cipher/Mode/Mode.h> | ||||
| 
 | ||||
| namespace Crypto { | ||||
| namespace Cipher { | ||||
| 
 | ||||
| template <typename T> | ||||
| class CBC : public Mode<T> { | ||||
| public: | ||||
|     template <typename... Args> | ||||
|     explicit constexpr CBC<T>(Args... args) | ||||
|         : Mode<T>(args...) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     virtual Optional<ByteBuffer> encrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) override | ||||
|     { | ||||
|         auto length = in.size(); | ||||
|         if (length == 0) | ||||
|             return {}; | ||||
| 
 | ||||
|         auto& cipher = this->cipher(); | ||||
| 
 | ||||
|         // FIXME: We should have two of these encrypt/decrypt functions that
 | ||||
|         //        we SFINAE out based on whether the Cipher mode needs an ivec
 | ||||
|         ASSERT(ivec.has_value()); | ||||
|         const auto* iv = ivec.value().data(); | ||||
| 
 | ||||
|         typename T::BlockType block { cipher.padding_mode() }; | ||||
|         size_t offset { 0 }; | ||||
|         auto block_size = cipher.block_size(); | ||||
| 
 | ||||
|         while (length >= block_size) { | ||||
|             block.overwrite(in.slice_view(offset, block_size)); | ||||
|             block.apply_initialization_vector(iv); | ||||
|             cipher.encrypt_block(block, block); | ||||
|             out.overwrite(offset, block.get().data(), block_size); | ||||
|             iv = out.offset_pointer(offset); | ||||
|             length -= block_size; | ||||
|             offset += block_size; | ||||
|     template <typename T> | ||||
|     class CBC : public Mode<T> { | ||||
|     public: | ||||
|         template <typename... Args> | ||||
|         explicit constexpr CBC<T>(Args... args) | ||||
|             : Mode<T>(args...) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         if (length > 0) { | ||||
|             block.overwrite(in.slice_view(offset, length)); | ||||
|             block.apply_initialization_vector(iv); | ||||
|             cipher.encrypt_block(block, block); | ||||
|             out.overwrite(offset, block.get().data(), block_size); | ||||
|             iv = out.offset_pointer(offset); | ||||
|         virtual Optional<ByteBuffer> encrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) override | ||||
|         { | ||||
|             auto length = in.size(); | ||||
|             if (length == 0) | ||||
|                 return {}; | ||||
| 
 | ||||
|             auto& cipher = this->cipher(); | ||||
| 
 | ||||
|             // FIXME: We should have two of these encrypt/decrypt functions that
 | ||||
|             //        we SFINAE out based on whether the Cipher mode needs an ivec
 | ||||
|             ASSERT(ivec.has_value()); | ||||
|             const auto* iv = ivec.value().data(); | ||||
| 
 | ||||
|             typename T::BlockType block { cipher.padding_mode() }; | ||||
|             size_t offset { 0 }; | ||||
|             auto block_size = cipher.block_size(); | ||||
| 
 | ||||
|             while (length >= block_size) { | ||||
|                 block.overwrite(in.slice_view(offset, block_size)); | ||||
|                 block.apply_initialization_vector(iv); | ||||
|                 cipher.encrypt_block(block, block); | ||||
|                 out.overwrite(offset, block.get().data(), block_size); | ||||
|                 iv = out.offset_pointer(offset); | ||||
|                 length -= block_size; | ||||
|                 offset += block_size; | ||||
|             } | ||||
| 
 | ||||
|             if (length > 0) { | ||||
|                 block.overwrite(in.slice_view(offset, length)); | ||||
|                 block.apply_initialization_vector(iv); | ||||
|                 cipher.encrypt_block(block, block); | ||||
|                 out.overwrite(offset, block.get().data(), block_size); | ||||
|                 iv = out.offset_pointer(offset); | ||||
|             } | ||||
| 
 | ||||
|             return ByteBuffer::copy(iv, block_size); | ||||
|         } | ||||
|         virtual void decrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) override | ||||
|         { | ||||
|             auto length = in.size(); | ||||
|             if (length == 0) | ||||
|                 return; | ||||
| 
 | ||||
|         return ByteBuffer::copy(iv, block_size); | ||||
|     } | ||||
|     virtual void decrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) override | ||||
|     { | ||||
|         auto length = in.size(); | ||||
|         if (length == 0) | ||||
|             return; | ||||
|             auto& cipher = this->cipher(); | ||||
| 
 | ||||
|         auto& cipher = this->cipher(); | ||||
|             ASSERT(ivec.has_value()); | ||||
|             const auto* iv = ivec.value().data(); | ||||
| 
 | ||||
|         ASSERT(ivec.has_value()); | ||||
|         const auto* iv = ivec.value().data(); | ||||
|             auto block_size = cipher.block_size(); | ||||
| 
 | ||||
|         auto block_size = cipher.block_size(); | ||||
|             // if the data is not aligned, it's not correct encrypted data
 | ||||
|             // FIXME (ponder): Should we simply decrypt as much as we can?
 | ||||
|             ASSERT(length % block_size == 0); | ||||
| 
 | ||||
|         // if the data is not aligned, it's not correct encrypted data
 | ||||
|         // FIXME (ponder): Should we simply decrypt as much as we can?
 | ||||
|         ASSERT(length % block_size == 0); | ||||
|             typename T::BlockType block { cipher.padding_mode() }; | ||||
|             size_t offset { 0 }; | ||||
| 
 | ||||
|         typename T::BlockType block { cipher.padding_mode() }; | ||||
|         size_t offset { 0 }; | ||||
| 
 | ||||
|         while (length > 0) { | ||||
|             auto* slice = in.offset_pointer(offset); | ||||
|             block.overwrite(slice, block_size); | ||||
|             cipher.decrypt_block(block, block); | ||||
|             block.apply_initialization_vector(iv); | ||||
|             auto decrypted = block.get(); | ||||
|             out.overwrite(offset, decrypted.data(), decrypted.size()); | ||||
|             iv = slice; | ||||
|             length -= block_size; | ||||
|             offset += block_size; | ||||
|             while (length > 0) { | ||||
|                 auto* slice = in.offset_pointer(offset); | ||||
|                 block.overwrite(slice, block_size); | ||||
|                 cipher.decrypt_block(block, block); | ||||
|                 block.apply_initialization_vector(iv); | ||||
|                 auto decrypted = block.get(); | ||||
|                 out.overwrite(offset, decrypted.data(), decrypted.size()); | ||||
|                 iv = slice; | ||||
|                 length -= block_size; | ||||
|                 offset += block_size; | ||||
|             } | ||||
|             this->prune_padding(out); | ||||
|         } | ||||
|         this->prune_padding(out); | ||||
|     } | ||||
| }; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -30,68 +30,71 @@ | |||
| #include <LibCrypto/Cipher/Cipher.h> | ||||
| 
 | ||||
| namespace Crypto { | ||||
| namespace Cipher { | ||||
| 
 | ||||
| template <typename T> | ||||
| class Mode { | ||||
| public: | ||||
|     // FIXME: Somehow communicate that encrypt returns the last initialization vector (if the mode supports it)
 | ||||
|     virtual Optional<ByteBuffer> encrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) = 0; | ||||
|     virtual void decrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) = 0; | ||||
|     template <typename T> | ||||
|     class Mode { | ||||
|     public: | ||||
|         // FIXME: Somehow communicate that encrypt returns the last initialization vector (if the mode supports it)
 | ||||
|         virtual Optional<ByteBuffer> encrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) = 0; | ||||
|         virtual void decrypt(const ByteBuffer& in, ByteBuffer& out, Optional<ByteBuffer> ivec = {}) = 0; | ||||
| 
 | ||||
|     const T& cipher() const { return m_cipher; } | ||||
|         const T& cipher() const { return m_cipher; } | ||||
| 
 | ||||
|     ByteBuffer create_aligned_buffer(size_t input_size) const | ||||
|     { | ||||
|         size_t remainder = (input_size + T::block_size()) % T::block_size(); | ||||
|         if (remainder == 0) | ||||
|             return ByteBuffer::create_uninitialized(input_size); | ||||
|         else | ||||
|             return ByteBuffer::create_uninitialized(input_size + T::block_size() - remainder); | ||||
|     } | ||||
|         ByteBuffer create_aligned_buffer(size_t input_size) const | ||||
|         { | ||||
|             size_t remainder = (input_size + T::block_size()) % T::block_size(); | ||||
|             if (remainder == 0) | ||||
|                 return ByteBuffer::create_uninitialized(input_size); | ||||
|             else | ||||
|                 return ByteBuffer::create_uninitialized(input_size + T::block_size() - remainder); | ||||
|         } | ||||
| 
 | ||||
| protected: | ||||
|     T& cipher() { return m_cipher; } | ||||
|     protected: | ||||
|         T& cipher() { return m_cipher; } | ||||
| 
 | ||||
|     virtual void prune_padding(ByteBuffer& data) | ||||
|     { | ||||
|         auto size = data.size(); | ||||
|         switch (m_cipher.padding_mode()) { | ||||
|         case PaddingMode::CMS: { | ||||
|             auto maybe_padding_length = data[size - 1]; | ||||
|             if (maybe_padding_length >= T::block_size()) { | ||||
|                 // cannot be padding (the entire block cannot be padding)
 | ||||
|                 return; | ||||
|             } | ||||
|             for (auto i = maybe_padding_length; i > 0; --i) { | ||||
|                 if (data[size - i] != maybe_padding_length) { | ||||
|                     // not padding, part of data
 | ||||
|         virtual void prune_padding(ByteBuffer& data) | ||||
|         { | ||||
|             auto size = data.size(); | ||||
|             switch (m_cipher.padding_mode()) { | ||||
|             case PaddingMode::CMS: { | ||||
|                 auto maybe_padding_length = data[size - 1]; | ||||
|                 if (maybe_padding_length >= T::block_size()) { | ||||
|                     // cannot be padding (the entire block cannot be padding)
 | ||||
|                     return; | ||||
|                 } | ||||
|                 for (auto i = maybe_padding_length; i > 0; --i) { | ||||
|                     if (data[size - i] != maybe_padding_length) { | ||||
|                         // not padding, part of data
 | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|                 data.trim(size - maybe_padding_length); | ||||
|                 break; | ||||
|             } | ||||
|             case PaddingMode::Null: { | ||||
|                 while (data[size - 1] == 0) | ||||
|                     --size; | ||||
|                 data.trim(size); | ||||
|                 break; | ||||
|             } | ||||
|             default: | ||||
|                 // FIXME: support other padding modes
 | ||||
|                 ASSERT_NOT_REACHED(); | ||||
|                 break; | ||||
|             } | ||||
|             data.trim(size - maybe_padding_length); | ||||
|             break; | ||||
|         } | ||||
|         case PaddingMode::Null: { | ||||
|             while (data[size - 1] == 0) | ||||
|                 --size; | ||||
|             data.trim(size); | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             // FIXME: support other padding modes
 | ||||
|             ASSERT_NOT_REACHED(); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // FIXME: Somehow add a reference version of this
 | ||||
|     template <typename... Args> | ||||
|     Mode(Args... args) | ||||
|         : m_cipher(args...) | ||||
|     { | ||||
|     } | ||||
|         // FIXME: Somehow add a reference version of this
 | ||||
|         template <typename... Args> | ||||
|         Mode(Args... args) | ||||
|             : m_cipher(args...) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         T m_cipher; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| private: | ||||
|     T m_cipher; | ||||
| }; | ||||
| } | ||||
|  |  | |||
|  | @ -31,21 +31,24 @@ | |||
| #include <AK/Types.h> | ||||
| 
 | ||||
| namespace Crypto { | ||||
| namespace Hash { | ||||
| 
 | ||||
| template<size_t BlockS, typename DigestT> | ||||
| class HashFunction { | ||||
| public: | ||||
|     static constexpr auto BlockSize = BlockS; | ||||
|     using DigestType = DigestT; | ||||
|     template <size_t BlockS, typename DigestT> | ||||
|     class HashFunction { | ||||
|     public: | ||||
|         static constexpr auto BlockSize = BlockS / 8; | ||||
|         static constexpr auto DigestSize = sizeof(DigestT); | ||||
| 
 | ||||
|     static size_t block_size() { return BlockSize; }; | ||||
|     static size_t digest_size() { return sizeof(DigestType); }; | ||||
|         using DigestType = DigestT; | ||||
| 
 | ||||
|     virtual void update(const u8*, size_t) = 0; | ||||
|     virtual void update(const ByteBuffer& buffer) = 0; | ||||
|     virtual void update(const StringView& string) = 0; | ||||
|         static size_t block_size() { return BlockSize; }; | ||||
|         static size_t digest_size() { return DigestSize; }; | ||||
| 
 | ||||
|     virtual DigestType digest() = 0; | ||||
| }; | ||||
|         virtual void update(const u8*, size_t) = 0; | ||||
|         virtual void update(const ByteBuffer& buffer) = 0; | ||||
|         virtual void update(const StringView& string) = 0; | ||||
| 
 | ||||
|         virtual DigestType digest() = 0; | ||||
|     }; | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -65,167 +65,168 @@ static constexpr inline void round_4(u32& a, u32 b, u32 c, u32 d, u32 x, u32 s, | |||
| } | ||||
| 
 | ||||
| namespace Crypto { | ||||
| namespace Hash { | ||||
| 
 | ||||
| void MD5::update(const u8* input, size_t length) | ||||
| { | ||||
|     auto index = (u32)(m_count[0] >> 3) & 0x3f; | ||||
|     size_t offset { 0 }; | ||||
|     m_count[0] += (u32)length << 3; | ||||
|     if (m_count[0] < ((u32)length << 3)) { | ||||
|         ++m_count[1]; | ||||
|     void MD5::update(const u8* input, size_t length) | ||||
|     { | ||||
|         auto index = (u32)(m_count[0] >> 3) & 0x3f; | ||||
|         size_t offset { 0 }; | ||||
|         m_count[0] += (u32)length << 3; | ||||
|         if (m_count[0] < ((u32)length << 3)) { | ||||
|             ++m_count[1]; | ||||
|         } | ||||
|         m_count[1] += (u32)length >> 29; | ||||
| 
 | ||||
|         auto part_length = 64 - index; | ||||
|         if (length >= part_length) { | ||||
|             m_buffer.overwrite(index, input, part_length); | ||||
|             transform(m_buffer.data()); | ||||
| 
 | ||||
|             for (offset = part_length; offset + 63 < length; offset += 64) | ||||
|                 transform(&input[offset]); | ||||
| 
 | ||||
|             index = 0; | ||||
|         } | ||||
|         ASSERT(length < part_length || length - offset <= 64); | ||||
|         m_buffer.overwrite(index, &input[offset], length - offset); | ||||
|     } | ||||
|     m_count[1] += (u32)length >> 29; | ||||
|     MD5::DigestType MD5::digest() | ||||
|     { | ||||
|         DigestType digest; | ||||
|         u8 bits[8]; | ||||
| 
 | ||||
|     auto part_length = 64 - index; | ||||
|     if (length >= part_length) { | ||||
|         m_buffer.overwrite(index, input, part_length); | ||||
|         transform(m_buffer.data()); | ||||
|         encode(m_count, bits, 8); | ||||
| 
 | ||||
|         for (offset = part_length; offset + 63 < length; offset += 64) | ||||
|             transform(&input[offset]); | ||||
|         // pad the data to 56%64
 | ||||
|         u32 index = (u32)((m_count[0] >> 3) & 0x3f); | ||||
|         u32 pad_length = index < 56 ? 56 - index : 120 - index; | ||||
|         update(MD5Constants::PADDING, pad_length); | ||||
| 
 | ||||
|         index = 0; | ||||
|         // append length
 | ||||
|         update(bits, 8); | ||||
| 
 | ||||
|         // store state (4 registers ABCD)
 | ||||
|         encode(&m_A, digest.data, 4 * sizeof(m_A)); | ||||
| 
 | ||||
|         reset(); | ||||
| 
 | ||||
|         return digest; | ||||
|     } | ||||
| 
 | ||||
|     ASSERT(length < part_length || length - offset <= 64); | ||||
|     m_buffer.overwrite(index, &input[offset], length - offset); | ||||
| } | ||||
| MD5::DigestType MD5::digest() | ||||
| { | ||||
|     DigestType digest; | ||||
|     u8 bits[8]; | ||||
| 
 | ||||
|     encode(m_count, bits, 8); | ||||
| 
 | ||||
|     // pad the data to 56%64
 | ||||
|     u32 index = (u32)((m_count[0] >> 3) & 0x3f); | ||||
|     u32 pad_length = index < 56 ? 56 - index : 120 - index; | ||||
|     update(Constants::PADDING, pad_length); | ||||
| 
 | ||||
|     // append length
 | ||||
|     update(bits, 8); | ||||
| 
 | ||||
|     // store state (4 registers ABCD)
 | ||||
|     encode(&m_A, digest.data, 4 * sizeof(m_A)); | ||||
| 
 | ||||
|     reset(); | ||||
| 
 | ||||
|     return digest; | ||||
| } | ||||
| 
 | ||||
| void MD5::encode(const u32* from, u8* to, size_t length) | ||||
| { | ||||
|     for (size_t i = 0, j = 0; j < length; ++i, j += 4) { | ||||
|         to[j] = (u8)(from[i] & 0xff); | ||||
|         to[j + 1] = (u8)((from[i] >> 8) & 0xff); | ||||
|         to[j + 2] = (u8)((from[i] >> 16) & 0xff); | ||||
|         to[j + 3] = (u8)((from[i] >> 24) & 0xff); | ||||
|     void MD5::encode(const u32* from, u8* to, size_t length) | ||||
|     { | ||||
|         for (size_t i = 0, j = 0; j < length; ++i, j += 4) { | ||||
|             to[j] = (u8)(from[i] & 0xff); | ||||
|             to[j + 1] = (u8)((from[i] >> 8) & 0xff); | ||||
|             to[j + 2] = (u8)((from[i] >> 16) & 0xff); | ||||
|             to[j + 3] = (u8)((from[i] >> 24) & 0xff); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MD5::decode(const u8* from, u32* to, size_t length) | ||||
| { | ||||
|     for (size_t i = 0, j = 0; j < length; ++i, j += 4) | ||||
|         to[i] = (((u32)from[j]) | (((u32)from[j + 1]) << 8) | (((u32)from[j + 2]) << 16) | (((u32)from[j + 3]) << 24)); | ||||
| } | ||||
|     void MD5::decode(const u8* from, u32* to, size_t length) | ||||
|     { | ||||
|         for (size_t i = 0, j = 0; j < length; ++i, j += 4) | ||||
|             to[i] = (((u32)from[j]) | (((u32)from[j + 1]) << 8) | (((u32)from[j + 2]) << 16) | (((u32)from[j + 3]) << 24)); | ||||
|     } | ||||
| 
 | ||||
| void MD5::transform(const u8* block) | ||||
| { | ||||
|     auto a = m_A; | ||||
|     auto b = m_B; | ||||
|     auto c = m_C; | ||||
|     auto d = m_D; | ||||
|     u32 x[16]; | ||||
|     void MD5::transform(const u8* block) | ||||
|     { | ||||
|         auto a = m_A; | ||||
|         auto b = m_B; | ||||
|         auto c = m_C; | ||||
|         auto d = m_D; | ||||
|         u32 x[16]; | ||||
| 
 | ||||
|     decode(block, x, 64); | ||||
|         decode(block, x, 64); | ||||
| 
 | ||||
|     round_1(a, b, c, d, x[0], Constants::S11, 0xd76aa478); // 1
 | ||||
|     round_1(d, a, b, c, x[1], Constants::S12, 0xe8c7b756); // 2
 | ||||
|     round_1(c, d, a, b, x[2], Constants::S13, 0x242070db); // 3
 | ||||
|     round_1(b, c, d, a, x[3], Constants::S14, 0xc1bdceee); // 4
 | ||||
|     round_1(a, b, c, d, x[4], Constants::S11, 0xf57c0faf); // 5
 | ||||
|     round_1(d, a, b, c, x[5], Constants::S12, 0x4787c62a); // 6
 | ||||
|     round_1(c, d, a, b, x[6], Constants::S13, 0xa8304613); // 7
 | ||||
|     round_1(b, c, d, a, x[7], Constants::S14, 0xfd469501); // 8
 | ||||
|     round_1(a, b, c, d, x[8], Constants::S11, 0x698098d8); // 9
 | ||||
|     round_1(d, a, b, c, x[9], Constants::S12, 0x8b44f7af); // 10
 | ||||
|     round_1(c, d, a, b, x[10], Constants::S13, 0xffff5bb1); // 11
 | ||||
|     round_1(b, c, d, a, x[11], Constants::S14, 0x895cd7be); // 12
 | ||||
|     round_1(a, b, c, d, x[12], Constants::S11, 0x6b901122); // 13
 | ||||
|     round_1(d, a, b, c, x[13], Constants::S12, 0xfd987193); // 14
 | ||||
|     round_1(c, d, a, b, x[14], Constants::S13, 0xa679438e); // 15
 | ||||
|     round_1(b, c, d, a, x[15], Constants::S14, 0x49b40821); // 16
 | ||||
|         round_1(a, b, c, d, x[0], MD5Constants::S11, 0xd76aa478); // 1
 | ||||
|         round_1(d, a, b, c, x[1], MD5Constants::S12, 0xe8c7b756); // 2
 | ||||
|         round_1(c, d, a, b, x[2], MD5Constants::S13, 0x242070db); // 3
 | ||||
|         round_1(b, c, d, a, x[3], MD5Constants::S14, 0xc1bdceee); // 4
 | ||||
|         round_1(a, b, c, d, x[4], MD5Constants::S11, 0xf57c0faf); // 5
 | ||||
|         round_1(d, a, b, c, x[5], MD5Constants::S12, 0x4787c62a); // 6
 | ||||
|         round_1(c, d, a, b, x[6], MD5Constants::S13, 0xa8304613); // 7
 | ||||
|         round_1(b, c, d, a, x[7], MD5Constants::S14, 0xfd469501); // 8
 | ||||
|         round_1(a, b, c, d, x[8], MD5Constants::S11, 0x698098d8); // 9
 | ||||
|         round_1(d, a, b, c, x[9], MD5Constants::S12, 0x8b44f7af); // 10
 | ||||
|         round_1(c, d, a, b, x[10], MD5Constants::S13, 0xffff5bb1); // 11
 | ||||
|         round_1(b, c, d, a, x[11], MD5Constants::S14, 0x895cd7be); // 12
 | ||||
|         round_1(a, b, c, d, x[12], MD5Constants::S11, 0x6b901122); // 13
 | ||||
|         round_1(d, a, b, c, x[13], MD5Constants::S12, 0xfd987193); // 14
 | ||||
|         round_1(c, d, a, b, x[14], MD5Constants::S13, 0xa679438e); // 15
 | ||||
|         round_1(b, c, d, a, x[15], MD5Constants::S14, 0x49b40821); // 16
 | ||||
| 
 | ||||
|     round_2(a, b, c, d, x[1], Constants::S21, 0xf61e2562); // 17
 | ||||
|     round_2(d, a, b, c, x[6], Constants::S22, 0xc040b340); // 18
 | ||||
|     round_2(c, d, a, b, x[11], Constants::S23, 0x265e5a51); // 19
 | ||||
|     round_2(b, c, d, a, x[0], Constants::S24, 0xe9b6c7aa); // 20
 | ||||
|     round_2(a, b, c, d, x[5], Constants::S21, 0xd62f105d); // 21
 | ||||
|     round_2(d, a, b, c, x[10], Constants::S22, 0x2441453); // 22
 | ||||
|     round_2(c, d, a, b, x[15], Constants::S23, 0xd8a1e681); // 23
 | ||||
|     round_2(b, c, d, a, x[4], Constants::S24, 0xe7d3fbc8); // 24
 | ||||
|     round_2(a, b, c, d, x[9], Constants::S21, 0x21e1cde6); // 25
 | ||||
|     round_2(d, a, b, c, x[14], Constants::S22, 0xc33707d6); // 26
 | ||||
|     round_2(c, d, a, b, x[3], Constants::S23, 0xf4d50d87); // 27
 | ||||
|     round_2(b, c, d, a, x[8], Constants::S24, 0x455a14ed); // 28
 | ||||
|     round_2(a, b, c, d, x[13], Constants::S21, 0xa9e3e905); // 29
 | ||||
|     round_2(d, a, b, c, x[2], Constants::S22, 0xfcefa3f8); // 30
 | ||||
|     round_2(c, d, a, b, x[7], Constants::S23, 0x676f02d9); // 31
 | ||||
|     round_2(b, c, d, a, x[12], Constants::S24, 0x8d2a4c8a); // 32
 | ||||
|         round_2(a, b, c, d, x[1], MD5Constants::S21, 0xf61e2562); // 17
 | ||||
|         round_2(d, a, b, c, x[6], MD5Constants::S22, 0xc040b340); // 18
 | ||||
|         round_2(c, d, a, b, x[11], MD5Constants::S23, 0x265e5a51); // 19
 | ||||
|         round_2(b, c, d, a, x[0], MD5Constants::S24, 0xe9b6c7aa); // 20
 | ||||
|         round_2(a, b, c, d, x[5], MD5Constants::S21, 0xd62f105d); // 21
 | ||||
|         round_2(d, a, b, c, x[10], MD5Constants::S22, 0x2441453); // 22
 | ||||
|         round_2(c, d, a, b, x[15], MD5Constants::S23, 0xd8a1e681); // 23
 | ||||
|         round_2(b, c, d, a, x[4], MD5Constants::S24, 0xe7d3fbc8); // 24
 | ||||
|         round_2(a, b, c, d, x[9], MD5Constants::S21, 0x21e1cde6); // 25
 | ||||
|         round_2(d, a, b, c, x[14], MD5Constants::S22, 0xc33707d6); // 26
 | ||||
|         round_2(c, d, a, b, x[3], MD5Constants::S23, 0xf4d50d87); // 27
 | ||||
|         round_2(b, c, d, a, x[8], MD5Constants::S24, 0x455a14ed); // 28
 | ||||
|         round_2(a, b, c, d, x[13], MD5Constants::S21, 0xa9e3e905); // 29
 | ||||
|         round_2(d, a, b, c, x[2], MD5Constants::S22, 0xfcefa3f8); // 30
 | ||||
|         round_2(c, d, a, b, x[7], MD5Constants::S23, 0x676f02d9); // 31
 | ||||
|         round_2(b, c, d, a, x[12], MD5Constants::S24, 0x8d2a4c8a); // 32
 | ||||
| 
 | ||||
|     round_3(a, b, c, d, x[5], Constants::S31, 0xfffa3942); // 33
 | ||||
|     round_3(d, a, b, c, x[8], Constants::S32, 0x8771f681); // 34
 | ||||
|     round_3(c, d, a, b, x[11], Constants::S33, 0x6d9d6122); // 35
 | ||||
|     round_3(b, c, d, a, x[14], Constants::S34, 0xfde5380c); // 36
 | ||||
|     round_3(a, b, c, d, x[1], Constants::S31, 0xa4beea44); // 37
 | ||||
|     round_3(d, a, b, c, x[4], Constants::S32, 0x4bdecfa9); // 38
 | ||||
|     round_3(c, d, a, b, x[7], Constants::S33, 0xf6bb4b60); // 39
 | ||||
|     round_3(b, c, d, a, x[10], Constants::S34, 0xbebfbc70); // 40
 | ||||
|     round_3(a, b, c, d, x[13], Constants::S31, 0x289b7ec6); // 41
 | ||||
|     round_3(d, a, b, c, x[0], Constants::S32, 0xeaa127fa); // 42
 | ||||
|     round_3(c, d, a, b, x[3], Constants::S33, 0xd4ef3085); // 43
 | ||||
|     round_3(b, c, d, a, x[6], Constants::S34, 0x4881d05); // 44
 | ||||
|     round_3(a, b, c, d, x[9], Constants::S31, 0xd9d4d039); // 45
 | ||||
|     round_3(d, a, b, c, x[12], Constants::S32, 0xe6db99e5); // 46
 | ||||
|     round_3(c, d, a, b, x[15], Constants::S33, 0x1fa27cf8); // 47
 | ||||
|     round_3(b, c, d, a, x[2], Constants::S34, 0xc4ac5665); // 48
 | ||||
|         round_3(a, b, c, d, x[5], MD5Constants::S31, 0xfffa3942); // 33
 | ||||
|         round_3(d, a, b, c, x[8], MD5Constants::S32, 0x8771f681); // 34
 | ||||
|         round_3(c, d, a, b, x[11], MD5Constants::S33, 0x6d9d6122); // 35
 | ||||
|         round_3(b, c, d, a, x[14], MD5Constants::S34, 0xfde5380c); // 36
 | ||||
|         round_3(a, b, c, d, x[1], MD5Constants::S31, 0xa4beea44); // 37
 | ||||
|         round_3(d, a, b, c, x[4], MD5Constants::S32, 0x4bdecfa9); // 38
 | ||||
|         round_3(c, d, a, b, x[7], MD5Constants::S33, 0xf6bb4b60); // 39
 | ||||
|         round_3(b, c, d, a, x[10], MD5Constants::S34, 0xbebfbc70); // 40
 | ||||
|         round_3(a, b, c, d, x[13], MD5Constants::S31, 0x289b7ec6); // 41
 | ||||
|         round_3(d, a, b, c, x[0], MD5Constants::S32, 0xeaa127fa); // 42
 | ||||
|         round_3(c, d, a, b, x[3], MD5Constants::S33, 0xd4ef3085); // 43
 | ||||
|         round_3(b, c, d, a, x[6], MD5Constants::S34, 0x4881d05); // 44
 | ||||
|         round_3(a, b, c, d, x[9], MD5Constants::S31, 0xd9d4d039); // 45
 | ||||
|         round_3(d, a, b, c, x[12], MD5Constants::S32, 0xe6db99e5); // 46
 | ||||
|         round_3(c, d, a, b, x[15], MD5Constants::S33, 0x1fa27cf8); // 47
 | ||||
|         round_3(b, c, d, a, x[2], MD5Constants::S34, 0xc4ac5665); // 48
 | ||||
| 
 | ||||
|     round_4(a, b, c, d, x[0], Constants::S41, 0xf4292244); // 49
 | ||||
|     round_4(d, a, b, c, x[7], Constants::S42, 0x432aff97); // 50
 | ||||
|     round_4(c, d, a, b, x[14], Constants::S43, 0xab9423a7); // 51
 | ||||
|     round_4(b, c, d, a, x[5], Constants::S44, 0xfc93a039); // 52
 | ||||
|     round_4(a, b, c, d, x[12], Constants::S41, 0x655b59c3); // 53
 | ||||
|     round_4(d, a, b, c, x[3], Constants::S42, 0x8f0ccc92); // 54
 | ||||
|     round_4(c, d, a, b, x[10], Constants::S43, 0xffeff47d); // 55
 | ||||
|     round_4(b, c, d, a, x[1], Constants::S44, 0x85845dd1); // 56
 | ||||
|     round_4(a, b, c, d, x[8], Constants::S41, 0x6fa87e4f); // 57
 | ||||
|     round_4(d, a, b, c, x[15], Constants::S42, 0xfe2ce6e0); // 58
 | ||||
|     round_4(c, d, a, b, x[6], Constants::S43, 0xa3014314); // 59
 | ||||
|     round_4(b, c, d, a, x[13], Constants::S44, 0x4e0811a1); // 60
 | ||||
|     round_4(a, b, c, d, x[4], Constants::S41, 0xf7537e82); // 61
 | ||||
|     round_4(d, a, b, c, x[11], Constants::S42, 0xbd3af235); // 62
 | ||||
|     round_4(c, d, a, b, x[2], Constants::S43, 0x2ad7d2bb); // 63
 | ||||
|     round_4(b, c, d, a, x[9], Constants::S44, 0xeb86d391); // 64
 | ||||
|         round_4(a, b, c, d, x[0], MD5Constants::S41, 0xf4292244); // 49
 | ||||
|         round_4(d, a, b, c, x[7], MD5Constants::S42, 0x432aff97); // 50
 | ||||
|         round_4(c, d, a, b, x[14], MD5Constants::S43, 0xab9423a7); // 51
 | ||||
|         round_4(b, c, d, a, x[5], MD5Constants::S44, 0xfc93a039); // 52
 | ||||
|         round_4(a, b, c, d, x[12], MD5Constants::S41, 0x655b59c3); // 53
 | ||||
|         round_4(d, a, b, c, x[3], MD5Constants::S42, 0x8f0ccc92); // 54
 | ||||
|         round_4(c, d, a, b, x[10], MD5Constants::S43, 0xffeff47d); // 55
 | ||||
|         round_4(b, c, d, a, x[1], MD5Constants::S44, 0x85845dd1); // 56
 | ||||
|         round_4(a, b, c, d, x[8], MD5Constants::S41, 0x6fa87e4f); // 57
 | ||||
|         round_4(d, a, b, c, x[15], MD5Constants::S42, 0xfe2ce6e0); // 58
 | ||||
|         round_4(c, d, a, b, x[6], MD5Constants::S43, 0xa3014314); // 59
 | ||||
|         round_4(b, c, d, a, x[13], MD5Constants::S44, 0x4e0811a1); // 60
 | ||||
|         round_4(a, b, c, d, x[4], MD5Constants::S41, 0xf7537e82); // 61
 | ||||
|         round_4(d, a, b, c, x[11], MD5Constants::S42, 0xbd3af235); // 62
 | ||||
|         round_4(c, d, a, b, x[2], MD5Constants::S43, 0x2ad7d2bb); // 63
 | ||||
|         round_4(b, c, d, a, x[9], MD5Constants::S44, 0xeb86d391); // 64
 | ||||
| 
 | ||||
|     m_A += a; | ||||
|     m_B += b; | ||||
|     m_C += c; | ||||
|     m_D += d; | ||||
|         m_A += a; | ||||
|         m_B += b; | ||||
|         m_C += c; | ||||
|         m_D += d; | ||||
| 
 | ||||
|     __builtin_memset(x, 0, sizeof(x)); | ||||
| } | ||||
|         __builtin_memset(x, 0, sizeof(x)); | ||||
|     } | ||||
| 
 | ||||
| void MD5::reset() | ||||
| { | ||||
|     m_A = Constants::init_A; | ||||
|     m_B = Constants::init_B; | ||||
|     m_C = Constants::init_C; | ||||
|     m_D = Constants::init_D; | ||||
|     void MD5::reset() | ||||
|     { | ||||
|         m_A = MD5Constants::init_A; | ||||
|         m_B = MD5Constants::init_B; | ||||
|         m_C = MD5Constants::init_C; | ||||
|         m_D = MD5Constants::init_D; | ||||
| 
 | ||||
|     m_count[0] = 0; | ||||
|     m_count[1] = 0; | ||||
|         m_count[0] = 0; | ||||
|         m_count[1] = 0; | ||||
| 
 | ||||
|     __builtin_memset(m_data_buffer, 0, sizeof(m_data_buffer)); | ||||
| } | ||||
|         __builtin_memset(m_data_buffer, 0, sizeof(m_data_buffer)); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -30,78 +30,78 @@ | |||
| #include <LibCrypto/Hash/HashFunction.h> | ||||
| 
 | ||||
| namespace Crypto { | ||||
| namespace Hash { | ||||
| 
 | ||||
| struct MD5Digest { | ||||
|     u8 data[16]; | ||||
| }; | ||||
|     struct MD5Digest { | ||||
|         u8 data[16]; | ||||
|     }; | ||||
| 
 | ||||
| namespace MD5Constants { | ||||
|     namespace MD5Constants { | ||||
| 
 | ||||
| constexpr u32 init_A = 0x67452301; | ||||
| constexpr u32 init_B = 0xefcdab89; | ||||
| constexpr u32 init_C = 0x98badcfe; | ||||
| constexpr u32 init_D = 0x10325476; | ||||
| constexpr u32 S11 = 7; | ||||
| constexpr u32 S12 = 12; | ||||
| constexpr u32 S13 = 17; | ||||
| constexpr u32 S14 = 22; | ||||
| constexpr u32 S21 = 5; | ||||
| constexpr u32 S22 = 9; | ||||
| constexpr u32 S23 = 14; | ||||
| constexpr u32 S24 = 20; | ||||
| constexpr u32 S31 = 4; | ||||
| constexpr u32 S32 = 11; | ||||
| constexpr u32 S33 = 16; | ||||
| constexpr u32 S34 = 23; | ||||
| constexpr u32 S41 = 6; | ||||
| constexpr u32 S42 = 10; | ||||
| constexpr u32 S43 = 15; | ||||
| constexpr u32 S44 = 21; | ||||
| constexpr u8 PADDING[] = { | ||||
|     0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|     0 | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| class MD5 final : public HashFunction<16, MD5Digest> { | ||||
| public: | ||||
|     MD5() | ||||
|     { | ||||
|         m_buffer = ByteBuffer::wrap(m_data_buffer, sizeof(m_data_buffer)); | ||||
|         constexpr u32 init_A = 0x67452301; | ||||
|         constexpr u32 init_B = 0xefcdab89; | ||||
|         constexpr u32 init_C = 0x98badcfe; | ||||
|         constexpr u32 init_D = 0x10325476; | ||||
|         constexpr u32 S11 = 7; | ||||
|         constexpr u32 S12 = 12; | ||||
|         constexpr u32 S13 = 17; | ||||
|         constexpr u32 S14 = 22; | ||||
|         constexpr u32 S21 = 5; | ||||
|         constexpr u32 S22 = 9; | ||||
|         constexpr u32 S23 = 14; | ||||
|         constexpr u32 S24 = 20; | ||||
|         constexpr u32 S31 = 4; | ||||
|         constexpr u32 S32 = 11; | ||||
|         constexpr u32 S33 = 16; | ||||
|         constexpr u32 S34 = 23; | ||||
|         constexpr u32 S41 = 6; | ||||
|         constexpr u32 S42 = 10; | ||||
|         constexpr u32 S43 = 15; | ||||
|         constexpr u32 S44 = 21; | ||||
|         constexpr u8 PADDING[] = { | ||||
|             0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||||
|             0 | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     virtual void update(const u8*, size_t) override; | ||||
|     virtual void update(const ByteBuffer& buffer) override { update(buffer.data(), buffer.size()); }; | ||||
|     virtual void update(const StringView& string) override { update((const u8*)string.characters_without_null_termination(), string.length()); }; | ||||
|     virtual DigestType digest() override; | ||||
|     class MD5 final : public HashFunction<512, MD5Digest> { | ||||
|     public: | ||||
|         MD5() | ||||
|         { | ||||
|             m_buffer = ByteBuffer::wrap(m_data_buffer, sizeof(m_data_buffer)); | ||||
|         } | ||||
| 
 | ||||
|     inline static DigestType hash(const u8* data, size_t length) | ||||
|     { | ||||
|         MD5 md5; | ||||
|         md5.update(data, length); | ||||
|         return md5.digest(); | ||||
|     } | ||||
|         virtual void update(const u8*, size_t) override; | ||||
|         virtual void update(const ByteBuffer& buffer) override { update(buffer.data(), buffer.size()); }; | ||||
|         virtual void update(const StringView& string) override { update((const u8*)string.characters_without_null_termination(), string.length()); }; | ||||
|         virtual DigestType digest() override; | ||||
| 
 | ||||
|     inline static DigestType hash(const ByteBuffer& buffer) { return hash(buffer.data(), buffer.size()); } | ||||
|     inline static DigestType hash(const StringView& buffer) { return hash((const u8*)buffer.characters_without_null_termination(), buffer.length()); } | ||||
|         inline static DigestType hash(const u8* data, size_t length) | ||||
|         { | ||||
|             MD5 md5; | ||||
|             md5.update(data, length); | ||||
|             return md5.digest(); | ||||
|         } | ||||
| 
 | ||||
| private: | ||||
|     inline void transform(const u8*); | ||||
|     inline void reset(); | ||||
|         inline static DigestType hash(const ByteBuffer& buffer) { return hash(buffer.data(), buffer.size()); } | ||||
|         inline static DigestType hash(const StringView& buffer) { return hash((const u8*)buffer.characters_without_null_termination(), buffer.length()); } | ||||
| 
 | ||||
|     static void encode(const u32* from, u8* to, size_t length); | ||||
|     static void decode(const u8* from, u32* to, size_t length); | ||||
|     private: | ||||
|         inline void transform(const u8*); | ||||
|         inline void reset(); | ||||
| 
 | ||||
|     u32 m_A { Constants::init_A }, m_B { Constants::init_B }, m_C { Constants::init_C }, m_D { Constants::init_D }; | ||||
|     u32 m_count[2] { 0, 0 }; | ||||
|     ByteBuffer m_buffer; | ||||
|         static void encode(const u32* from, u8* to, size_t length); | ||||
|         static void decode(const u8* from, u32* to, size_t length); | ||||
| 
 | ||||
|     u8 m_data_buffer[64]; | ||||
| }; | ||||
|         u32 m_A { MD5Constants::init_A }, m_B { MD5Constants::init_B }, m_C { MD5Constants::init_C }, m_D { MD5Constants::init_D }; | ||||
|         u32 m_count[2] { 0, 0 }; | ||||
|         ByteBuffer m_buffer; | ||||
| 
 | ||||
|         u8 m_data_buffer[64]; | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -68,10 +68,10 @@ void aes_cbc(const char* message, size_t len) | |||
| { | ||||
|     auto buffer = ByteBuffer::wrap(message, len); | ||||
|     // FIXME: Take iv as an optional parameter
 | ||||
|     auto iv = ByteBuffer::create_zeroed(Crypto::AESCipher::block_size()); | ||||
|     auto iv = ByteBuffer::create_zeroed(Crypto::Cipher::AESCipher::block_size()); | ||||
| 
 | ||||
|     if (encrypting) { | ||||
|         Crypto::AESCipher::CBCMode cipher(secret_key, key_bits, Crypto::Intent::Encryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher(secret_key, key_bits, Crypto::Cipher::Intent::Encryption); | ||||
| 
 | ||||
|         auto enc = cipher.create_aligned_buffer(buffer.size()); | ||||
|         cipher.encrypt(buffer, enc, iv); | ||||
|  | @ -79,9 +79,9 @@ void aes_cbc(const char* message, size_t len) | |||
|         if (binary) | ||||
|             printf("%.*s", (int)enc.size(), enc.data()); | ||||
|         else | ||||
|             print_buffer(enc, Crypto::AESCipher::block_size()); | ||||
|             print_buffer(enc, Crypto::Cipher::AESCipher::block_size()); | ||||
|     } else { | ||||
|         Crypto::AESCipher::CBCMode cipher(secret_key, key_bits, Crypto::Intent::Decryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher(secret_key, key_bits, Crypto::Cipher::Intent::Decryption); | ||||
|         auto dec = cipher.create_aligned_buffer(buffer.size()); | ||||
|         cipher.decrypt(buffer, dec, iv); | ||||
|         printf("%.*s\n", (int)dec.size(), dec.data()); | ||||
|  | @ -90,11 +90,21 @@ void aes_cbc(const char* message, size_t len) | |||
| 
 | ||||
| void md5(const char* message, size_t len) | ||||
| { | ||||
|     auto digest = Crypto::MD5::hash((const u8*)message, len); | ||||
|     auto digest = Crypto::Hash::MD5::hash((const u8*)message, len); | ||||
|     if (binary) | ||||
|         printf("%.*s", (int)Crypto::MD5::block_size(), digest.data); | ||||
|         printf("%.*s", (int)Crypto::Hash::MD5::digest_size(), digest.data); | ||||
|     else | ||||
|         print_buffer(ByteBuffer::wrap(digest.data, Crypto::MD5::block_size()), Crypto::MD5::block_size()); | ||||
|         print_buffer(ByteBuffer::wrap(digest.data, Crypto::Hash::MD5::digest_size()), -1); | ||||
| } | ||||
| 
 | ||||
| void hmac_md5(const char* message, size_t len) | ||||
| { | ||||
|     Crypto::Authentication::HMAC<Crypto::Hash::MD5> hmac(secret_key); | ||||
|     auto mac = hmac.process((const u8*)message, len); | ||||
|     if (binary) | ||||
|         printf("%.*s", (int)hmac.DigestSize, mac.data); | ||||
|     else | ||||
|         print_buffer(ByteBuffer::wrap(mac.data, hmac.DigestSize), -1); | ||||
| } | ||||
| 
 | ||||
| auto main(int argc, char** argv) -> int | ||||
|  | @ -103,7 +113,7 @@ auto main(int argc, char** argv) -> int | |||
|     Core::ArgsParser parser; | ||||
|     parser.add_positional_argument(mode, "mode to operate in ('list' to see modes and descriptions)", "mode"); | ||||
| 
 | ||||
|     parser.add_option(secret_key, "Set the secret key (must be key-bits bits)", "secret-key", 'k', "secret key"); | ||||
|     parser.add_option(secret_key, "Set the secret key", "secret-key", 'k', "secret key"); | ||||
|     parser.add_option(key_bits, "Size of the key", "key-bits", 'b', "key-bits"); | ||||
|     parser.add_option(filename, "Read from file", "file", 'f', "from file"); | ||||
|     parser.add_option(binary, "Force binary output", "force-binary", 0); | ||||
|  | @ -143,7 +153,7 @@ auto main(int argc, char** argv) -> int | |||
|             if (run_tests) | ||||
|                 return aes_cbc_tests(); | ||||
| 
 | ||||
|             if (!Crypto::AESCipher::KeyType::is_valid_key_size(key_bits)) { | ||||
|             if (!Crypto::Cipher::AESCipher::KeyType::is_valid_key_size(key_bits)) { | ||||
|                 printf("Invalid key size for AES: %d\n", key_bits); | ||||
|                 return 1; | ||||
|             } | ||||
|  | @ -199,13 +209,13 @@ void aes_cbc_test_encrypt() | |||
|     auto test_it = [](auto& cipher, auto& result) { | ||||
|         auto in = "This is a test! This is another test!"_b; | ||||
|         auto out = cipher.create_aligned_buffer(in.size()); | ||||
|         auto iv = ByteBuffer::create_zeroed(Crypto::AESCipher::block_size()); | ||||
|         auto iv = ByteBuffer::create_zeroed(Crypto::Cipher::AESCipher::block_size()); | ||||
|         cipher.encrypt(in, out, iv); | ||||
|         if (out.size() != sizeof(result)) | ||||
|             FAIL(size mismatch); | ||||
|         else if (memcmp(out.data(), result, out.size()) != 0) { | ||||
|             FAIL(invalid data); | ||||
|             print_buffer(out, Crypto::AESCipher::block_size()); | ||||
|             print_buffer(out, Crypto::Cipher::AESCipher::block_size()); | ||||
|         } else | ||||
|             PASS; | ||||
|     }; | ||||
|  | @ -217,7 +227,7 @@ void aes_cbc_test_encrypt() | |||
|             0x8b, 0xd3, 0x70, 0x45, 0xf0, 0x79, 0x65, 0xca, 0xb9, 0x03, 0x88, 0x72, 0x1c, 0xdd, 0xab, | ||||
|             0x45, 0x6b, 0x1c | ||||
|         }; | ||||
|         Crypto::AESCipher::CBCMode cipher("WellHelloFriends", 128, Crypto::Intent::Encryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher("WellHelloFriends", 128, Crypto::Cipher::Intent::Encryption); | ||||
|         test_it(cipher, result); | ||||
|     } | ||||
|     { | ||||
|  | @ -228,7 +238,7 @@ void aes_cbc_test_encrypt() | |||
|             0x68, 0x51, 0x09, 0xd7, 0x3b, 0x48, 0x1b, 0x8a, 0xd3, 0x50, 0x09, 0xba, 0xfc, 0xde, 0x11, | ||||
|             0xe0, 0x3f, 0xcb | ||||
|         }; | ||||
|         Crypto::AESCipher::CBCMode cipher("Well Hello Friends! whf!", 192, Crypto::Intent::Encryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher("Well Hello Friends! whf!", 192, Crypto::Cipher::Intent::Encryption); | ||||
|         test_it(cipher, result); | ||||
|     } | ||||
|     { | ||||
|  | @ -239,7 +249,7 @@ void aes_cbc_test_encrypt() | |||
|             0x47, 0x9f, 0xc2, 0x21, 0xe6, 0x19, 0x62, 0xc3, 0x75, 0xca, 0xab, 0x2d, 0x18, 0xa1, 0x54, | ||||
|             0xd1, 0x41, 0xe6 | ||||
|         }; | ||||
|         Crypto::AESCipher::CBCMode cipher("WellHelloFriendsWellHelloFriends", 256, Crypto::Intent::Encryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher("WellHelloFriendsWellHelloFriends", 256, Crypto::Cipher::Intent::Encryption); | ||||
|         test_it(cipher, result); | ||||
|     } | ||||
|     // TODO: Test non-CMS padding options
 | ||||
|  | @ -250,14 +260,14 @@ void aes_cbc_test_decrypt() | |||
|         auto true_value = "This is a test! This is another test!"; | ||||
|         auto in = ByteBuffer::copy(result, result_len); | ||||
|         auto out = cipher.create_aligned_buffer(in.size()); | ||||
|         auto iv = ByteBuffer::create_zeroed(Crypto::AESCipher::block_size()); | ||||
|         auto iv = ByteBuffer::create_zeroed(Crypto::Cipher::AESCipher::block_size()); | ||||
|         cipher.decrypt(in, out, iv); | ||||
|         if (out.size() != strlen(true_value)) { | ||||
|             FAIL(size mismatch); | ||||
|             printf("Expected %zu bytes but got %zu\n", strlen(true_value), out.size()); | ||||
|         } else if (memcmp(out.data(), true_value, strlen(true_value)) != 0) { | ||||
|             FAIL(invalid data); | ||||
|             print_buffer(out, Crypto::AESCipher::block_size()); | ||||
|             print_buffer(out, Crypto::Cipher::AESCipher::block_size()); | ||||
|         } else | ||||
|             PASS; | ||||
|     }; | ||||
|  | @ -269,7 +279,7 @@ void aes_cbc_test_decrypt() | |||
|             0x8b, 0xd3, 0x70, 0x45, 0xf0, 0x79, 0x65, 0xca, 0xb9, 0x03, 0x88, 0x72, 0x1c, 0xdd, 0xab, | ||||
|             0x45, 0x6b, 0x1c | ||||
|         }; | ||||
|         Crypto::AESCipher::CBCMode cipher("WellHelloFriends", 128, Crypto::Intent::Decryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher("WellHelloFriends", 128, Crypto::Cipher::Intent::Decryption); | ||||
|         test_it(cipher, result, 48); | ||||
|     } | ||||
|     { | ||||
|  | @ -280,7 +290,7 @@ void aes_cbc_test_decrypt() | |||
|             0x68, 0x51, 0x09, 0xd7, 0x3b, 0x48, 0x1b, 0x8a, 0xd3, 0x50, 0x09, 0xba, 0xfc, 0xde, 0x11, | ||||
|             0xe0, 0x3f, 0xcb | ||||
|         }; | ||||
|         Crypto::AESCipher::CBCMode cipher("Well Hello Friends! whf!", 192, Crypto::Intent::Decryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher("Well Hello Friends! whf!", 192, Crypto::Cipher::Intent::Decryption); | ||||
|         test_it(cipher, result, 48); | ||||
|     } | ||||
|     { | ||||
|  | @ -291,7 +301,7 @@ void aes_cbc_test_decrypt() | |||
|             0x47, 0x9f, 0xc2, 0x21, 0xe6, 0x19, 0x62, 0xc3, 0x75, 0xca, 0xab, 0x2d, 0x18, 0xa1, 0x54, | ||||
|             0xd1, 0x41, 0xe6 | ||||
|         }; | ||||
|         Crypto::AESCipher::CBCMode cipher("WellHelloFriendsWellHelloFriends", 256, Crypto::Intent::Decryption); | ||||
|         Crypto::Cipher::AESCipher::CBCMode cipher("WellHelloFriendsWellHelloFriends", 256, Crypto::Cipher::Intent::Decryption); | ||||
|         test_it(cipher, result, 48); | ||||
|     } | ||||
|     // TODO: Test non-CMS padding options
 | ||||
|  | @ -311,11 +321,11 @@ void md5_test_hash() | |||
|         u8 result[] { | ||||
|             0xaf, 0x04, 0x3a, 0x08, 0x94, 0x38, 0x6e, 0x7f, 0xbf, 0x73, 0xe4, 0xaa, 0xf0, 0x8e, 0xee, 0x4c | ||||
|         }; | ||||
|         auto digest = Crypto::MD5::hash("Well hello friends"); | ||||
|         auto digest = Crypto::Hash::MD5::hash("Well hello friends"); | ||||
| 
 | ||||
|         if (memcmp(result, digest.data, Crypto::MD5::block_size()) != 0) { | ||||
|         if (memcmp(result, digest.data, Crypto::Hash::MD5::digest_size()) != 0) { | ||||
|             FAIL(Invalid hash); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::MD5::block_size()), -1); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::Hash::MD5::digest_size()), -1); | ||||
|         } else { | ||||
|             PASS; | ||||
|         } | ||||
|  | @ -326,11 +336,11 @@ void md5_test_hash() | |||
|         u8 result[] { | ||||
|             0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e | ||||
|         }; | ||||
|         auto digest = Crypto::MD5::hash(""); | ||||
|         auto digest = Crypto::Hash::MD5::hash(""); | ||||
| 
 | ||||
|         if (memcmp(result, digest.data, Crypto::MD5::block_size()) != 0) { | ||||
|         if (memcmp(result, digest.data, Crypto::Hash::MD5::digest_size()) != 0) { | ||||
|             FAIL(Invalid hash); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::MD5::block_size()), -1); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::Hash::MD5::digest_size()), -1); | ||||
|         } else { | ||||
|             PASS; | ||||
|         } | ||||
|  | @ -340,11 +350,11 @@ void md5_test_hash() | |||
|         u8 result[] { | ||||
|             0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 | ||||
|         }; | ||||
|         auto digest = Crypto::MD5::hash("a"); | ||||
|         auto digest = Crypto::Hash::MD5::hash("a"); | ||||
| 
 | ||||
|         if (memcmp(result, digest.data, Crypto::MD5::block_size()) != 0) { | ||||
|         if (memcmp(result, digest.data, Crypto::Hash::MD5::digest_size()) != 0) { | ||||
|             FAIL(Invalid hash); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::MD5::block_size()), -1); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::Hash::MD5::digest_size()), -1); | ||||
|         } else { | ||||
|             PASS; | ||||
|         } | ||||
|  | @ -354,11 +364,11 @@ void md5_test_hash() | |||
|         u8 result[] { | ||||
|             0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b | ||||
|         }; | ||||
|         auto digest = Crypto::MD5::hash("abcdefghijklmnopqrstuvwxyz"); | ||||
|         auto digest = Crypto::Hash::MD5::hash("abcdefghijklmnopqrstuvwxyz"); | ||||
| 
 | ||||
|         if (memcmp(result, digest.data, Crypto::MD5::block_size()) != 0) { | ||||
|         if (memcmp(result, digest.data, Crypto::Hash::MD5::digest_size()) != 0) { | ||||
|             FAIL(Invalid hash); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::MD5::block_size()), -1); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::Hash::MD5::digest_size()), -1); | ||||
|         } else { | ||||
|             PASS; | ||||
|         } | ||||
|  | @ -368,11 +378,11 @@ void md5_test_hash() | |||
|         u8 result[] { | ||||
|             0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a | ||||
|         }; | ||||
|         auto digest = Crypto::MD5::hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); | ||||
|         auto digest = Crypto::Hash::MD5::hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); | ||||
| 
 | ||||
|         if (memcmp(result, digest.data, Crypto::MD5::block_size()) != 0) { | ||||
|         if (memcmp(result, digest.data, Crypto::Hash::MD5::digest_size()) != 0) { | ||||
|             FAIL(Invalid hash); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::MD5::block_size()), -1); | ||||
|             print_buffer(ByteBuffer::wrap(digest.data, Crypto::Hash::MD5::digest_size()), -1); | ||||
|         } else { | ||||
|             PASS; | ||||
|         } | ||||
|  | @ -386,21 +396,21 @@ void md5_test_consecutive_updates() | |||
|         u8 result[] { | ||||
|             0xaf, 0x04, 0x3a, 0x08, 0x94, 0x38, 0x6e, 0x7f, 0xbf, 0x73, 0xe4, 0xaa, 0xf0, 0x8e, 0xee, 0x4c | ||||
|         }; | ||||
|         Crypto::MD5 md5; | ||||
|         Crypto::Hash::MD5 md5; | ||||
| 
 | ||||
|         md5.update("Well"); | ||||
|         md5.update(" hello "); | ||||
|         md5.update("friends"); | ||||
|         auto digest = md5.digest(); | ||||
| 
 | ||||
|         if (memcmp(result, digest.data, Crypto::MD5::block_size()) != 0) | ||||
|         if (memcmp(result, digest.data, Crypto::Hash::MD5::digest_size()) != 0) | ||||
|             FAIL(Invalid hash); | ||||
|         else | ||||
|             PASS; | ||||
|     } | ||||
|     { | ||||
|         I_TEST((MD5 Hashing | Reuse)); | ||||
|         Crypto::MD5 md5; | ||||
|         Crypto::Hash::MD5 md5; | ||||
| 
 | ||||
|         md5.update("Well"); | ||||
|         md5.update(" hello "); | ||||
|  | @ -412,7 +422,7 @@ void md5_test_consecutive_updates() | |||
|         md5.update("friends"); | ||||
|         auto digest1 = md5.digest(); | ||||
| 
 | ||||
|         if (memcmp(digest0.data, digest1.data, Crypto::MD5::block_size()) != 0) | ||||
|         if (memcmp(digest0.data, digest1.data, Crypto::Hash::MD5::block_size()) != 0) | ||||
|             FAIL(Cannot reuse); | ||||
|         else | ||||
|             PASS; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 AnotherTest
						AnotherTest