New open AES lib needs testing (pb inc. available)

For everything that's not in any way related to PureBasic. General chat etc...
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

New open AES lib needs testing (pb inc. available)

Post by Inf0Byt3 »

Found a nice little public domain code on the web for some AES 256 action (different from the one i posted before) and created an include for it. This time it all seems to work OK. My wrapper supports buffers of any size, e.g. the padding is done inside using one of the best methods (index byte padding) - that if i implemented it correctly. There's an example as well and the original C code is included (plus the PellesC project for easy compilation).

Now, could anyone make some tests on it (i did too) and see if it works ok? Also take a peek at the code in the include, there has to be something I didn't spot, i'm sure.

Also, how can a procedure return a structured variable? I hate using globals.

The code is here:
File:1->RIJNDAEL.zip
Image
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Re: New open AES lib needs testing (pb inc. available)

Post by Fluid Byte »

Inf0Byt3 wrote:Also, how can a procedure return a structured variable? I hate using globals.
Not quite sure if I understood correctly but something like this?

Code: Select all

Structure MYSTRUCT
	X.l
	Y.l
	Z.l
EndStructure

Procedure YadaYada(X,Y,Z)
	*mstr.MYSTRUCT = AllocateMemory(SizeOf(MYSTRUCT))
	*mstr\X = X
	*mstr\Y = Y
	*mstr\Z = Z
	
	ProcedureReturn *mstr
EndProcedure

*mstr.MYSTRUCT = YadaYada(10,20,30)

Debug *mstr\X
Debug *mstr\Y
Debug *mstr\Z
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Yup, that will do, thanks! I'll slip it in.

[Edit]
Archive updated :).
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Improved it again. Added a new member for the 'result', e.g to know if the enc/dec was done and a SHA256 lib so you can use any password length (for AES256 you needed a fixed 256bit = 32bytes password). Of course, all the calculations are done by the functions themselves, e.g. it's very easy to use.

Hopefully there won't be any problems, but let me know if you find anything. The link is the same (see first post).
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Fixed some bugs in the padding proc. and in the encryption/decryption code. The address for the lib is the same.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

I am currently working on a general StringManager wich offers the option to encrypt the strings. At the moment this is done via simple XOR but I will switch to AES now since it's a really powerfull encryption. So thanks for this Inf0Byt3. :wink:

One question though, for AES256 the password always have to be exactly 32 chars long? I assume it can't be longer but shorter? I ask because I remember your earlier AES version supported passwords of any length. Or was I just using it incorrectly back then?
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

I am currently working on a general StringManager wich offers the option to encrypt the strings. At the moment this is done via simple XOR but I will switch to AES now since it's a really powerfull encryption. So thanks for this Inf0Byt3. Wink
I'm very glad it is of use :D. My only hope is that I didn't miss anything that would screw things up. I've been using this for a while now and it seems to be pretty stable.
One question though, for AES256 the password always have to be exactly 32 chars long? I assume it can't be longer but shorter? I ask because I remember your earlier AES version supported passwords of any length. Or was I just using it incorrectly back then?
I think it has to be 256 bit big (256bit / 8bits = 32 bytes of key length), this seems to be the way AES works. This particular build uses 32 byte keys and blocks of 16 bytes.

However in the latest version I added a SHA2 fingerprint that allows you to use any key length now. First the password is hashed then that 32 byte hash is used to encrypt / decrypt the data. So now your password can be as big as you want :).

Oh and something i forgot to tell you, after you encrypt or decrypt, make sure to free that structured variable as well:

Code: Select all

*Ret.RetAES = AES_Encrypt(@a,Len(a),@b,Len(b))
;now the encryption function has allocated that structure and has put the results in it
;do what you want with the data
FreeMemory(*Ret\AES_RetAddrBuff) ;free the mem block
FreeMemory(*Ret) ;free the variable itself because it was allocated by the procedures themselves
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

Inf0Byt3 wrote:I'm very glad it is of use :D. My only hope is that I didn't miss anything that would screw things up. I've been using this for a while now and it seems to be pretty stable.
Yeah, seems pretty stable so far. I am just browsing through the code and doing some optimations like making it EnableExplicit-compatible, removing redundant operators/variable declarations and make it a little more readable (indention/blanks). This should help me to understand what's going on.
However in the latest version I added a SHA2 fingerprint that allows you to use any key length now.
The hash of the password is used to encrypt the input, got it now. :P

Two more things though ...

I read the Wikipedia article about this type of encryption and it seems that sometimes there can be "anomalies" wich would allow the hash to be reversed. But the needed amount of time and hardware equipment to find such anomalies would be beyond any imagination. So for my understanding I would consider it uncrackable and it only depends how you implement the password matching routine in your code.

I mean you should avoid constructs like

Code: Select all

If Password$ = "MYHASHCODE" ...
The second thing would be regarding the size of the input buffer. It can be of any size, that right? I ask because I intend to use it for large files as well by using buffered file access (e.g. chunks of 4096 bytes).
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

I read the Wikipedia article about this type of encryption and it seems that sometimes there can be "anomalies" wich would allow the hash to be reversed. But the needed amount of time and hardware equipment to find such anomalies would be beyond any imagination. So for my understanding I would consider it uncrackable and it only depends how you implement the password matching routine in your code.
Indeed, but SHA2 hasn't been cracked yet :). That's the good part, as MD5 can be replicated. And you can always make it harder to decrypt by encrypting the output again with simple XOR or RC4.

But the good thing is that you don't store that password's hash. The functions use the output of the hash function for encryption, but that value is not known by anybody and it's not stored inside the data. Basically this is uncrackable, as if they (as in crackers) obtain the hash they basically have the password. This way they got no information about the password, nor its length (because it's a 32 bytes fixed size in all cases).
I mean you should avoid constructs like

Code:
If Password$ = "MYHASHCODE" ...

The second thing would be regarding the size of the input buffer. It can be of any size, that right? I ask because I intend to use it for large files as well by using buffered file access (e.g. chunks of 4096 bytes).
The input buffer can be of any length as the procedures use padding. If the buffer does not contain a multiple of 16 bytes, it will get padded. The length of the output will be returned by that structured variable. If it is multiple of 16, then the procedure won't add anything.

About checking if the password is ok for files here's an idea:

Before encrypting the file, you get it's CRC32. Then you encrypt the file with the password, normally and store that CRC32 inside as well. Then, at decryption, you decrypt with the supplied password and re-hash the newly obtained, decrypted file. If the crc is the same with the one inside the file, it's all ok, the password was correct. This way you don't have to add information about the password itself in the file.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

Thank you for the quick tech info and the tip with the checksum.

Everything working as expected now. :D
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

That's great. Good luck with your program :D.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Fixed a tricky bug in the unpadding procedure (decryption). Surprisingly, even if it proved to work well in the tests and it would detect correctly if the data was previously padded (i tested with 16, 32, 48 and 64 bytes long buffers), if you used a normal, multiple of 16 buffer but longer, e.g. 128+ bytes, it would sometimes say that it was padded when it wasn't. The current version should fix this bug.

Also I added a smaller xor encryption loop inside that should protect the data if there are repetitions (as AES is a block cypher, this will make it act as a stream one).

The address for the lib is the same.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

Nope the decryption it ain't working well. I'm trying to fix it, there's something wrong with the unpadding. Please wait for a fix. If anyone got an idea post it here.

[Later edit]
I think i fixed it. Made some exhaustive tests with random length random buffers (50000 encryptions/decryptions), it doesn't leak memory and decrypts ok. There were definitely some problems there, mainly some calculations done wrong. Probably last time I try to wrap something this complicated :roll:.

Please test WELL before/if using. 2 tests are now included. Same link for the file.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
Inf0Byt3
PureBasic Fanatic
PureBasic Fanatic
Posts: 2236
Joined: Fri Dec 09, 2005 12:15 pm
Location: Elbonia

Post by Inf0Byt3 »

When reading about padding in general, there were several ways to employ. So while reading on different pages, i found the best way to do this by padding on the last block n bytes with the value n, where n is how much bytes are needed to complete the block to 16 bytes. The thing is that one put in practice, it's not feasible because you might have this buffer:

B(16) = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}

As you can see, all the values are "1" and the buffer length is multiple of 16, thus it doesn't need padding. BUT once the decryption checks for padding, it will read the last byte wich is 1 (in red). The rule says that we need to check backwards if "1" bytes of "1" exists. And it does! This will make the procedure strip the last byte, even if it wasn't needed, because the rule applied.

SO

While trying to understand how to make this work I found this:
(RFC2630) Each padding byte is the pad count (16 extra added if size is already a multiple of 16)
Basically in order to know if the buffer was padded, each padding byte is the pad count. And we did that. But 16 are extra added if size is already a multiple of 16 which we didn't. This was the mistake with the code...

Now, no matter what happens, we pad the buffer with strictly 1 to 16 bytes so any confusion is eliminated. We always pad, even if the buffer contains strictly 16 bytes.

That being said, I updated the code in the first post. Let me know if there are any problems.
None are more hopelessly enslaved than those who falsely believe they are free. (Goethe)
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Post by cas »

thanks for fixing decryption bug. works great now
Post Reply