-
Notifications
You must be signed in to change notification settings - Fork 2.2k
AES128-CTR replacement #3638
base: master
Are you sure you want to change the base?
AES128-CTR replacement #3638
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,9 +28,264 @@ | |
|
||
using namespace std; | ||
using namespace dev; | ||
using namespace dev::crypto; | ||
using namespace CryptoPP; | ||
|
||
namespace | ||
{ | ||
|
||
// This code is modified version of https://github.com/kokke/tiny-AES128-C. | ||
|
||
constexpr int Nb = 4; ///< Number of columns in a AES state. | ||
constexpr int Nk = 4; ///< The number of 32 bit words in a key. | ||
constexpr int c_keySize = 16; ///< Key length in bytes (128 bit). | ||
constexpr int Nr = 10; ///< The number of rounds in AES Cipher. | ||
|
||
using state_t = byte[4][4]; | ||
|
||
/// The lookup-tables. | ||
const byte sbox[256] = { | ||
//0 1 2 3 4 5 6 7 8 9 A B C D E F | ||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, | ||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, | ||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, | ||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, | ||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, | ||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, | ||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, | ||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, | ||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, | ||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, | ||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, | ||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, | ||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, | ||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, | ||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, | ||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 | ||
}; | ||
|
||
// The round constant word array, Rcon[i], contains the values given by | ||
// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) | ||
// Note that i starts at 1, not 0). | ||
const byte Rcon[255] = { | ||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, | ||
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, | ||
0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, | ||
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, | ||
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, | ||
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, | ||
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, | ||
0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, | ||
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, | ||
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, | ||
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, | ||
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, | ||
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, | ||
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, | ||
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, | ||
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb | ||
}; | ||
|
||
/// Produces Nb(Nr+1) round keys. The round keys are used in each round | ||
/// to decrypt the states. | ||
void keyExpansion(byte* roundKeys, byte const* key) | ||
{ | ||
int i; | ||
byte tempa[4]; // Used for the column/row operations | ||
|
||
// The first round key is the key itself. | ||
for (i = 0; i < Nk; ++i) | ||
{ | ||
roundKeys[(i * 4) + 0] = key[(i * 4) + 0]; | ||
roundKeys[(i * 4) + 1] = key[(i * 4) + 1]; | ||
roundKeys[(i * 4) + 2] = key[(i * 4) + 2]; | ||
roundKeys[(i * 4) + 3] = key[(i * 4) + 3]; | ||
} | ||
|
||
// All other round keys are found from the previous round keys. | ||
for(; (i < (Nb * (Nr + 1))); ++i) | ||
{ | ||
for (int j = 0; j < 4; ++j) | ||
{ | ||
tempa[j] = roundKeys[(i-1) * 4 + j]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hoped I will not have to decrypt this indexing :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, but this just looks like dynamite to me. Buffers passed as plain pointers with sizes resulting from formulas including weird constants, it is just too easy to confuse two constants here, and we don't really know how much this library is used, tested, etc. |
||
} | ||
if (i % Nk == 0) | ||
{ | ||
// This function rotates the 4 bytes in a word to the left once. | ||
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0] | ||
|
||
// Function RotWord() | ||
{ | ||
auto k = tempa[0]; | ||
tempa[0] = tempa[1]; | ||
tempa[1] = tempa[2]; | ||
tempa[2] = tempa[3]; | ||
tempa[3] = k; | ||
} | ||
|
||
// SubWord() is a function that takes a four-byte input word and | ||
// applies the S-box to each of the four bytes to produce an output word. | ||
|
||
// Function Subword() | ||
{ | ||
tempa[0] = sbox[tempa[0]]; | ||
tempa[1] = sbox[tempa[1]]; | ||
tempa[2] = sbox[tempa[2]]; | ||
tempa[3] = sbox[tempa[3]]; | ||
} | ||
|
||
tempa[0] = tempa[0] ^ Rcon[i/Nk]; | ||
} | ||
roundKeys[i * 4 + 0] = roundKeys[(i - Nk) * 4 + 0] ^ tempa[0]; | ||
roundKeys[i * 4 + 1] = roundKeys[(i - Nk) * 4 + 1] ^ tempa[1]; | ||
roundKeys[i * 4 + 2] = roundKeys[(i - Nk) * 4 + 2] ^ tempa[2]; | ||
roundKeys[i * 4 + 3] = roundKeys[(i - Nk) * 4 + 3] ^ tempa[3]; | ||
} | ||
} | ||
|
||
/// Adds the round key to state. | ||
/// The round key is added to the state by an XOR function. | ||
void addRoundKey(state_t* state, byte const* roundKeys, int round) | ||
{ | ||
for (int i = 0; i < 4; ++i) | ||
for (int j = 0; j < 4; ++j) | ||
(*state)[i][j] ^= roundKeys[round * Nb * 4 + i * Nb + j]; | ||
} | ||
|
||
/// Substitutes the values in the | ||
/// state matrix with values in an S-box. | ||
void subBytes(state_t* state) | ||
{ | ||
for (int i = 0; i < 4; ++i) | ||
for (int j = 0; j < 4; ++j) | ||
(*state)[j][i] = sbox[(*state)[j][i]]; | ||
} | ||
|
||
/// Shifts the rows in the state to the left. | ||
/// Each row is shifted with different offset. | ||
/// Offset = Row number. So the first row is not shifted. | ||
void shiftRows(state_t* state) | ||
{ | ||
byte temp; | ||
|
||
// Rotate first row 1 columns to left | ||
temp = (*state)[0][1]; | ||
(*state)[0][1] = (*state)[1][1]; | ||
(*state)[1][1] = (*state)[2][1]; | ||
(*state)[2][1] = (*state)[3][1]; | ||
(*state)[3][1] = temp; | ||
|
||
// Rotate second row 2 columns to left | ||
temp = (*state)[0][2]; | ||
(*state)[0][2] = (*state)[2][2]; | ||
(*state)[2][2] = temp; | ||
|
||
temp = (*state)[1][2]; | ||
(*state)[1][2] = (*state)[3][2]; | ||
(*state)[3][2] = temp; | ||
|
||
// Rotate third row 3 columns to left | ||
temp = (*state)[0][3]; | ||
(*state)[0][3] = (*state)[3][3]; | ||
(*state)[3][3] = (*state)[2][3]; | ||
(*state)[2][3] = (*state)[1][3]; | ||
(*state)[1][3] = temp; | ||
} | ||
|
||
inline byte xtime(byte x) | ||
{ | ||
return static_cast<byte>(x<<1) ^ (((x>>7) & 1) * 0x1b); | ||
} | ||
|
||
// MixColumns function mixes the columns of the state matrix | ||
void mixColumns(state_t* state) | ||
{ | ||
byte Tmp,Tm,t; | ||
for(auto i = 0; i < 4; ++i) | ||
{ | ||
t = (*state)[i][0]; | ||
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; | ||
Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; | ||
Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; | ||
Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; | ||
Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; | ||
} | ||
} | ||
|
||
// Cipher is the main function that encrypts the PlainText. | ||
void cipher(state_t* state, byte const* roundKeys) | ||
{ | ||
// Add the First round key to the state before starting the rounds. | ||
addRoundKey(state, roundKeys, 0); | ||
|
||
// There will be Nr rounds. | ||
// The first Nr-1 rounds are identical. | ||
// These Nr-1 rounds are executed in the loop below. | ||
for (int round = 1; round < Nr; ++round) | ||
{ | ||
subBytes(state); | ||
shiftRows(state); | ||
mixColumns(state); | ||
addRoundKey(state, roundKeys, round); | ||
} | ||
|
||
// The last round is given below. | ||
// The MixColumns function is not here in the last round. | ||
subBytes(state); | ||
shiftRows(state); | ||
addRoundKey(state, roundKeys, Nr); | ||
} | ||
|
||
void AES128_CTR_process_buffer(byte* output, const byte* input, size_t length, const byte* key, const byte* iv) | ||
{ | ||
state_t state; | ||
byte roundKeys[176]; // The array that stores the round keys. | ||
byte ctr[c_keySize]; | ||
|
||
std::copy(iv, iv + c_keySize, ctr); | ||
keyExpansion(roundKeys, key); | ||
|
||
for (size_t i = 0; i < length; ++i) | ||
{ | ||
if ((i & 0x0000000F) == 0) | ||
{ | ||
std::copy(std::begin(ctr), std::end(ctr), &state[0][0]); | ||
cipher(&state, roundKeys); | ||
|
||
for (int j = c_keySize - 1; j >= 0; --j) | ||
{ | ||
++(ctr[j]); | ||
|
||
if (ctr[j]) | ||
break; | ||
} | ||
} | ||
|
||
output[i] = (input[i]) ^ ((&state[0][0])[i & 0x0000000F]); | ||
} | ||
} | ||
|
||
} | ||
|
||
bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain) | ||
{ | ||
if (_k.size() != 16) | ||
return {}; | ||
|
||
bytes ret(_plain.size()); | ||
AES128_CTR_process_buffer(ret.data(), _plain.data(), _plain.size(), _k.data(), _iv.data()); | ||
return ret; | ||
} | ||
|
||
bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher) | ||
{ | ||
if (_k.size() != 16) | ||
return {}; | ||
|
||
bytesSec ret(_cipher.size()); | ||
AES128_CTR_process_buffer(ret.writable().data(), _cipher.data(), _cipher.size(), _k.data(), _iv.data()); | ||
return ret; | ||
} | ||
|
||
bytes dev::aesDecrypt(bytesConstRef _ivCipher, std::string const& _password, unsigned _rounds, bytesConstRef _salt) | ||
{ | ||
bytes pw = asBytes(_password); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please mention that it was released under the "unlicense", roughly equivalent to a release to the public domain.