kokke / tiny-aes-c Goto Github PK
View Code? Open in Web Editor NEWSmall portable AES128/192/256 in C
License: The Unlicense
Small portable AES128/192/256 in C
License: The Unlicense
In KeyExpansion, the line which initialize the first RoundKey should be
memcpy(RoundKey, Key, AES_KEYLEN);
Using AES_keyExpSize as the length of 'Key' causes memory issues.
I also think it is best that AES_init_ctx should have arrays initialization:
memset(ctx->RoundKey, 0, AES_keyExpSize); #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) memset(ctx->Iv, 0, AES_BLOCKLEN); #endif
End up looking like this:
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) { memset(ctx->RoundKey, 0, AES_keyExpSize); #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) memset(ctx->Iv, 0, AES_BLOCKLEN); #endif KeyExpansion(ctx->RoundKey, key); }
'BlockCopy' just copy 'KEYLEN' chars
Hey guys!
Wondering if you support multi platform use for ex:
Encrypt on armv7 (32 bit bi-endian) and decrypt on x86_64 (64 bit little endian).
Cheers,
Lucas.
If you reverse the indices used in the state array (state[i,j] becomes state[j,i]), in/out values become a direct copy of the state array in memory. I made some modifications so it does in place encryption/decryption without creating separate in/out/state copies.
Link to modified file:
http://pastebin.com/nYzYvvNp
How to use this code for file encryption? Any idea?
You asked for smaller AES implementations, here you are:
http://www.ti.com/tool/aes-128
http://dominik.cc/projekty/avr-aes/
Warning: They have the same timing vulnerability in GF multiplication.
Hi,
is possible decrypt openssl using openssl cmdline tool ?
i.e.,
generate a file encrypted with aes-128-c ebc and use openssl to check or decrypt ?
thanks!
Just noted that the CBC encrypt code does NOT apply the IV to the final block when the length of the plain text is not an exact multilple of KEYLEN. In this instance the if(remainders>0){ } code after the FOR loop is executed and in that section the IV is NOT applied.
keep up the good work
Hi!
It looks like Iv
can be used uninitialized in AES_CBC_encrypt_buffer()
if iv
parameter is 0.
AES_CBC_encrypt_buffer(input, output, size, key, 0):
{
...
if (iv != 0) // iv is 0, so next line is not executed
{
Iv = iv;
}
for (i = 0; i < length; i += BLOCKLEN)
{
XorWithIv(input); // this function uses Iv, which is not initialized!
The same thing with AES_CBC_decrypt_buffer()
.
I suggest adding default value for initial vector:
#if defined(CBC) && CBC
// Initial Vector used only for CBC mode
static const uint8_t * Iv;
static const uint8_t defaultIv[BLOCKLEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
#endif
and replace
if (iv != 0) // iv is 0, so next line is not executed
{
Iv = iv;
}
with
Iv = iv ? iv : defaultIv;
in AES_CBC_encrypt_buffer()
and AES_CBC_decrypt_buffer()
I tried compiling with a KEYLEN of 32 and it produces a segmentation fault while running.
(No seg fault occurs when it is set to 16)
I would like some example programs that can use this to encrypt or decrypt or both files on the filesystem as well (like opening a file, reading the data, encrypting/decrypting it, writing the data, closing the file). This is because I might be thinking of Making an exe compressor or something with this and (maybe zlib) if I can figure out memory zlib compressing as well.
The code uses global variables for key/iv this is horribly thread unsafe! I know this is supposed to be mcu implementation but yet passing arguments around should not be that big of an issue. At least the there could be an -DTHREADSAFE option to compile a thread safe version of this code.
At the beginning of the CBC encrypt/decrypt functions the contents of the input buffer is copied to the output buffer, this is also done for ECB mode. The initial copy in ECB mode is necessary, but seems to be redundant in the CBC functions. The exact same copy is later made in the for loop iterating through the AES blocks.
A visual inspection of AES128_CBC_encrypt_buffer()
and AES128_CBC_decrypt_buffer()
should confirm the issue.
The tests pass with the redundant copy removed.
Remove redundant call to BlockCopy()
in AES128_CBC_encrypt_buffer()
and AES128_CBC_decrypt_buffer()
.
I had a hunt through the pull requests and found the following un-merged requests that address this issue:
#18 Removes redundant copy, as well as other changes.
#23 Lots of fixes to CBC implementation including this redundant block copy.
This is a simple fix that can shave off a few redundant CPU cycles, unless the compiler is already optimising it out for you ๐
I am happy to prepare a pull request addressing this issue only, if there's interest.
cannot execute binary file: Exec format error
Hi, kokke.
I forked your code and used in my project.
I met a problem. Let me show you code.
In this functon:
void AES128_CBC_encrypt_buffer(
uint8_t* output, uint8_t* input,
uint32_t length, const uint8_t* key, const uint8_t* iv)
If I pass parameter "iv" and "iv" equals 0, then:
if(iv != 0) //cause iv equals 0, then static var Iv isn't assimented, Iv's default value maybe 0
{
Iv = (uint8_t*)iv;
}
and then:
static void XorWithIv(uint8_t* buf)
{
uint8_t i;
for(i = 0; i < KEYLEN; ++i)
{
//casue Iv isn't initialized, this line probably generates segmentfalut
buf[i] ^= Iv[i];
}
}
I use openssl encrypt a string, the result is "8oaoH1JOBl3+QgRoEc5l0pYF5aMN1+p7AT/xAgUIST8="
echo -n "1234567890abcdef" | openssl enc -K 2b7e151628aed2a6abf7158809cf4f3c -iv 000102030405060708090a0b0c0d0e0f -aes-128-cbc -base64
but when use functuon AES128_CBC_encrypt_buffer, the result(after base64) is
"8oaoH1JOBl3+QgRoEc5l0g=="
I has set the key and IV as same sa openssl
Why are there have two differnet result? Thank you!
How can i enable pading in AES128_CBC_encrypt_buffer
We are using the lib inside a mulitply-threads context and found it is not thread-safe. There are global variables are using to optimized some internal parameters delivery.
For instance:
static state_t* state;
static uint8_t RoundKey[keyExpSize];
static const uint8_t* Key;
After remove them, lib are working propertly under mulitply-threads.
I see in AES_CBC_encrypt_buffer code:
XorWithIv(input); memcpy(output, input, BLOCKLEN);
I was expecting something like:
memcpy(output, input, BLOCKLEN); XorWithIv(output);
Hi
When I use the tiny-AES128 for both encryption and decryption it is working fine. But when I try to decrypt the same with any other program I get a partial decryption. I am not very good at C. So I am not sure if I am doing something wrong or if there is a bug. Below is are the details.
Key & IV: same as in text.c
#uint8_t encrypt_key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
#uint8_t iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
Encrypted Hex: AE8384D8E0AF32B801DA80E5CD05D7E8E916E853CAB551AB91966F540694A4D9
Plain Text: AAA000000001#starnet000000000000
When I decrypting the same using pyaes (python) and online (http://aes.online-domain-tools.com/) I the following decrypted message.
AAA000000001#sta???ิ?9???8??
The message is garbled after sta. Please let me know what is wrong.
Thanks & Regards
Vijay
Hey,
Great bit of code, should save me from using openssl (hopefully)! Just curious, on this section what made you use a loop rather than just memcpy(output,input,KEYLEN) ?:
static void BlockCopy(uint8_t* output, uint8_t* input) { uint8_t i; for (i=0;i<KEYLEN;++i) { output[i] = input[i]; } }
Of course memcpy itself is a call and then another loop but it might on some computers/compilers it might be more optimised then byte by byte copying
Both modes work indeed as stated by the NIST. Adding a counter mode would be awesome since CBC can stil be used in BEAST and ECB is vulnerable to plaintext attacks.
I think it's the dashes.
uint8_t input[17] = "2014-02-20 13:27";
// strftime((char*)input, sizeof(input), "%Y-%m-%d %H %M", &tstruct);
std::cout << input<<"\n";
uint8_t output[ sizeof(input) +16];
AES128_ECB_encrypt(input, key, output);
size_t size = sizeof(output);
uint8_t decrypted[17];
AES128_ECB_decrypt(output, key, decrypted);
std::cout << decrypted<< "\n";
Hi,
I couldn't find another way to contact you so I'm using this.
Could you be kind enough to share some usage examples ?
I've seen the tests so I've managed to understand most of it, but I have problems trying to use a key longer then 16 bits.
Thank you
Hi, thanks for the great code. It looks really clean and elegant implementation, and I love the fact you have CBC, but sadly I can't get it to work.
I placed the files as-is in the libraries directory and just by including "aes.h" the program compiles but:
I noticed you said you have tested this in AVR. Can you pls. post instructions on how you got it working? Perhaps I am doing something wrong.
TIA,
Alex
The Rcon
array currently takes 255 bytes of ROM, but only its first 11 elements are accessed, since there are only 10 rounds. Therefore the remaining 244 elements should be removed. The first element can also be removed when the array index is adjusted by -1
.
The whole array can be replaced by starting a local variable uint8_t rcon = 0x01
and applying xtime
after each round, which is a little slower but eliminates the need for fixed constants.
Premise: I'm not confident with C.
Is there a way to use this method:
void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);
by passing (char* output, char* input, uint32_t length, const char* key, const char* iv) ?
Codding standards not suitable for world
Things like this:
void AES128_ECB_encrypt(uint8_t* input, const uint8_t* key, uint8_t *output);
void AES128_ECB_decrypt(uint8_t* input, const uint8_t* key, uint8_t *output);
Can be changed to:
void AES128_ECB_encrypt(const uint8_t* input, const uint8_t* key, uint8_t *output);
void AES128_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t *output);
In the test.c file, it does #include "aes.h"
as the library. This is incorrect and will lead to linker errors. Please replace that with #include "aes.c"
instead. Then it works fine at compilation. I'm only writing this because it may lead to confusion. Although I would like to know why the header file does not #include "aes.c"
. Seems a bit odd. Besides that, great library, really nice performance.
Am I supposed to add logic to generate iv values or is this built in somewhere?
I'm facing problem on encryption. It generating values here then 255. So how to manage that? Can you please share implementation of this code on AVR?
Hi,
In the CTR test (test.c), the test_xcrypt_ctr()
function is invoked twice, once for encryption, once for decryption. However, the only difference between both invocations is the printed string, not the transformed data. Both invocations transform the in
buffer and verify that the result is equal to the out
buffer. Instead, the second invocation should transform (decrypt) the out
buffer, and verify that the result is equal to the in
buffer.
The change in code to achieve that is trivial, and fortunately, that test too passes on my old 16-bit DSP. :-)
Thanks again for sharing.
Best regards,
Alain Mosnier
I want to use these files in the Android NDK but unable to convert the string passed from java end to convert in the uInt_8 array and return an output string as being dumb in C.
Please, can you make the methods so that the return the encrypted string as output string and accept an input as plain text so that I can implement it easily?
Also, I want to provide the iv and key in the string format.
So please take plainText = "plaintext", iv="iv_key213123", key="key_qwerwqer", and return the output as
cypherText.
Hope it makes sense?
The readme says,
GCC size output when only ECB mode is ...
but the command is
arm-none-eabi-gcc -Os -c aes.c -DCBC=0
Is that a typo?
The loop that starts for(i = 0; i < length; i+=KEYLEN) will always executes once provided that the length is non zero. When the input data length is < KEYLEN and >0 then BOTH this loop and the block following it that handles the final partial block ("remainders") get executed. This is clearly incorrect.
I feel that logically the for loop should be looping through whole blocks and the loop count should not be a pointer! so something like for(u8 b = 0;b<NumCompleteBlocks;NumCompleteBlocks++)
u8 = uint_8
One then must then either pad out input data BEFORE the for loop if length is <KEYLEN, or add a check in the remainders block to ensure the IV is applied if NumCompleteBlocks=0 but not otherwise.
Apologies but I am new to GIT and not sure of the correct protocols!
Thanks
I try to compile the test.c file and I obtain the following errors:
"_AES_CBC_decrypt_buffer", referenced from:
_test_decrypt_cbc in test-602b3e.o
"_AES_CBC_encrypt_buffer", referenced from:
_test_encrypt_cbc in test-602b3e.o
"_AES_ECB_decrypt", referenced from:
_test_decrypt_ecb in test-602b3e.o
"_AES_ECB_encrypt", referenced from:
_test_encrypt_ecb in test-602b3e.o
_test_encrypt_ecb_verbose in test-602b3e.o
Does someone know how to fix this? Thanks in advance.
Current CBC decryption implementation causes damage of Iv data when you reload your input buffer. So any next call of AES128_CBC_decrypt_buffer(out, in, size, NULL, NULL) causes invalid result. To solve it add new buffer for Iv data which filled in decrypt function before exit.
Also only the first some of these constants are actually used โ up to rcon[10] for AES-128 (as 11 round keys are needed).
rcon[0] is not used in AES algorithm.
The Rijndael variants with larger block sizes use more of these constants, up to rcon[29] for Rijndael with 128-bit keys and 256 bit blocks (needs 15 round keys of each 256 bit, which means 30 full rounds of key expansion, which means 29 calls to the key schedule core using the round constants).
(C) WiKi
hi,
I am compiling this program in windows machine.Please let me know to how to compile this program
gcc -o aes aes.c gives undefined ref errors
hello
while using this aes code in CBC mode, i want to use random number, what all are the changes required for the same
Thanks for the Support
I am using your code for an embedded application (thank you very much BTW) that decrypts packetized ciphertext on the fly. The cipher text arrives on my embedded box in a circular buffer. Your implementation relies on the previous input persisting across calls to be reused as the next IV. A simple fix is to declare Iv as a byte array and then replace the pointer assignment with a memcpy.
for (i = 0; i < length; i += KEYLEN)
{
BlockCopy(output, input);
state = (state_t*)output;
InvCipher();
XorWithIv(output);
#ifdef STATIC_INPUT_ONLY
Iv = input;
#else
memcpy(Iv,input,sizeof(Iv));
#endif
input += KEYLEN;
output += KEYLEN;
}
I still have concerns about the licensing and if the sentence is sufficient. Do you mind to add maybe a licence file to your respository with a license text like this http://choosealicense.com/licenses/unlicense/ (see also http://unlicense.org) to be sure on this?
Great work
Hi,
Correct me if I am wrong, but I believe the comment "buffer size MUST be multiple of AES_BLOCKLEN" is inaccurate for AES_CTR_xcrypt_buffer() (in aes.h).
What if it's not? I believe Wikipedia's description of the case:
would apply to this implementation.
Requiring padding for CTR would also, in my interpretation, fail to fulfill NIST SP 800-38A, that specifies padding for ECB, CBC, and CFB modes only.
In other words, I believe this implementation is better than advertised, and the comment should be updated to reflect that. :-)
Thanks for putting this implementation in the public domain.
Best regards,
Alain Mosnier
hi. I am a beginner of encrypt algorithm.
i want to compare the 'tiny-aes128-c' encrypt with openssl. but the encrypt results are different.
Here is my practice:
#include "aes.h"
#include <stdio.h>
void phex(uint8_t *str, int len)
{
int i;
for(i=0; i<len; ++i){
printf("%.2x ", str[i]);
}
printf("\n");
}
int main()
{
const uint8_t key[16] = {0x12, 0x23};
const uint8_t iv[16] = {0xF1, 0x23};
uint8_t in[16] = "1234567890abc";
uint8_t out[16];
AES128_CBC_encrypt_buffer(out, in, sizeof(in), key, iv);
phex(out, sizeof(out));
return 0;
}
the tiny-AES128-C encrypt result is:
fd a3 86 e1 51 3f 9f 4a 8b 21 84 ee b4 bd 79 3e
$echo "1234567890abc" > plain.txt
$openssl enc -aes-128-cbc -in plain.txt -out encrypt.txt -K 1223 -iv f123 -p
$xxd encrypt.txt
tiny-aes128-c:
fd a3 86 e1 51 3f 9f 4a 8b 21 84 ee b4 bd 79 3e
openssl:
c5 af 18 cb dd ee 99 23 03 74 6a 21 9b b6 3f 99
why is difference?
Thank you!
I started to add CBC mode to tiny-AES, but I realized I don't know what open source license the base code is under. Could you let us know in the readme?
Hi,
I was very glad to find this library but I noticed some little things in the source code that can slow down the encryption/decryption process.
All the multiplications are by 4 but it's a lot quicker to shift the number two times to the left when you don't have an hardware multiplier.
For example, this code :
for(i = 0; i < Nk; ++i)
{
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
}
could be changed to :
uint32_t i4;
for(i = 0; i < Nk; ++i)
{
i4 = i<<2;
RoundKey[(i4) + 0] = Key[(i4) + 0];
RoundKey[(i4) + 1] = Key[(i4) + 1];
RoundKey[(i4) + 2] = Key[(i4) + 2];
RoundKey[(i4) + 3] = Key[(i4) + 3];
}
Or in this case, you can also increment i by 4 in your for loop.
When encrypting the string, if the string is less than a multiple of 16, pad the string with hex zeros to make the length become an exact multiple of 16. In the final byte of the padded value, indicate as a character (1-x0f), the actual length of the data that is valid within the padded block.
If the string is exactly a multiple of 16 bytes, add a padded block of hex zeros. The final byte will contain hex zero, which states that none of the final block is used.
When decoding, examine the last block of 16 bytes. That final byte indicates how many characters of this last block are valid.
I use this technique elsewhere, When I get a chance I will post my solution. My solution works with ecb or with cypher block chaining mode.
The function strncmp() will stop comparing when it encounters a NULL character in either string. For example, given the following data, strncmp() would report 0 (match), whereas memcmp() would report non-zero (mismatch).
uint8_t buf1[] = {3, 0, 1, 2};
uint8_t buf2[] = {3, 0, 1, 3};
false_result = strncmp((char *)buf1, (char *)buf2, 4);
true_result = memcmp(buf1, buf2, 4);
Using memcmp() for comparing byte sequences which are not null-terminated strings will fix this problem.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.