Page 1 of 5

AES encryption algorithm PureBasic LIB available !

Posted: Thu Aug 12, 2004 5:22 pm
by newbie
Hi,

thanks to SEC from this forum, the PB community has now the possibility to use AES (Rijndael) by using the Sec's lib :

original thread : viewtopic.php?t=11943&postdays=0&postorder=asc&start=45
AES LIB : http://metawire.org/~sec/aesv2.zip
FIPS PDF document about AES : http://csrc.nist.gov/publications/fips/ ... ps-197.pdf

functions :

Code: Select all

AES128Decrypt(), AES128Encrypt()
AES192Decrypt(), AES192Encrypt()
AES256Decrypt(), AES256Encrypt()
FIPS test :

Code: Select all

;Test from fips-197.pdf
;PLAINTEXT: 00112233445566778899aabbccddeeff
;KEY: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f

Procedure.s bytetohex(bb.l)
hexnum.s = "0123456789abcdef"
bb = bb & $FF
ProcedureReturn PeekS(@hexnum+ (bb>>4),1) + PeekS(@hexnum+ (bb & $0F),1)
EndProcedure

plain.s=Space(16)
PokeB(@plain,0)
For i = 1 To 15
PokeB(@plain+i, PeekB(@plain+i-1)+$11)
Next i

key.s = Space(32)
For i = 0 To 31
PokeB(@key+i,i)
Next i

AES256Encrypt(@plain,@key) ; notice: plain/cipher is at same place


Debug "#####ciphertext#####"
For i = 0 To 15
Debug bytetohex(PeekB(@plain+i))
Next i

AES256Decrypt(@plain,@key) ; notice: plain/cipher is at same place

Debug "#####plaintext#####"
For i = 0 To 15
Debug bytetohex(PeekB(@plain+i))
Next i

;other functions included
;AES128/192Encrypt()
;AES128/192Decrypt()
This example is based on a single block of 16 bytes to encrypt.
To use it on data of any size, you can create two procedures to
encrypt/decrypt until the right position.
These procedure has too to do padding to fill the last incomplete block, because AES encrypt by block of 128 bits.

Thansk to SEC for his work ;)

EDIT : the code to use Sec's Lib below :
viewtopic.php?p=66818#66818

Posted: Thu Aug 12, 2004 7:50 pm
by Moonshine
Im getting a "connection refused" message when trying to get the .zip.

Posted: Thu Aug 12, 2004 7:56 pm
by newbie
I just tried and the link work.

Anyway I mirrored it here : http://perso.wanadoo.fr/jugesoftware/purebasic/aes.zip
MD5 : 9BF6CCD4B9300FD7706C07A129D7553E

Posted: Thu Aug 12, 2004 7:57 pm
by Moonshine
Thanks newbie, that worked :)

Re: AES encryption algorithm PureBasic LIB available !

Posted: Thu Aug 12, 2004 11:58 pm
by Max.²
newbie wrote:Hi,

thanks to SEC from this forum, the PB community has now the possibility to use AES (Rijndael) by using the Sec's lib :
Darn, I knew that my work on AES 3 weeks ago will go unnoticed. Such things always happen. :lol:

viewtopic.php?t=11837&start=15&postdays ... highlight=
http://www.host4scripts.de/pub/AES.zip

A bit more generic, but the good thing is, both libs come to the same result with the same keys and input:

Code: Select all

;--- 01 Introduction
;
; Sample program For the AES PureBasic Library by Max., 24. July 2004
; The library was generated out of the C source code by Brian Gladman (http://fp.gladman.plus.com/index.htm)
; The sample is a conversion from VisualBasic, also provided by Brian Gladman.
; Download Link for the PureBasic related project files:
; http://www.host4scripts.de/pub/AES.zip
 
version.s = "2004072401"
 
;--- 02 misc variables and structures
 
#BlockLengthMax = 32           ; maximum block length in bytes
#KeyLengthMax = 32             ; maximum block length in bytes
#KeyScheduleLengthMax = 64     ; maximum key schedule length in bytes
 
Structure TCtx
    Ekey.l[#KeyScheduleLengthMax]
EndStructure
 
Structure TKey
    K.b[#KeyLengthMax]
EndStructure
 
Structure TInOut
    IO.b[#BlockLengthMax]
EndStructure
 
;--- 03 Debug output of the chosen key in Hex (not needed except for debugging)
 
Procedure OutKey(S.s,*B.TKey,KeyL.l)
    Debug ""
    Debug S.s
 
    For i = 0 To KeyL-1
        Debug Hex (*B\k[i] & $ff) ;Output unsigned byte value
    Next i
    
EndProcedure
 
;--- 04 Debug output of the encrypted/decrypted buffers in Hex (not needed except for debugging)
 
Procedure OutBlock(S.s,*B.TInOut)
    Debug ""
    Debug S.s
    For i = 0 To 15
        Debug Hex (*B\IO[i] & $ff) ;Output unsigned byte value
    Next i
EndProcedure
 
Key.TKey    ;holding the chosen key
Ib.TInOut   ;unencrypted input
Ob.TInOut   ;encrypted from input to output
Rb.TInOut   ;decrypted from output; should hold the same content as Ib
 
Ecx.TCtx ;encryption context
Dcx.TCtx ;decryption context
 
;--- 05 Initializing the variables to 0 values, then generating the AES tables
 
For i=0 To #KeyLengthMax-1
    Debug i
    Key\k[i] = 0
Next i
 
For i=0 To #BlockLengthMax-1
    Ib\IO[i] = 0
    Ob\IO[i] = 0
    Rb\IO[i] = 0
Next i
 
;snippet by PB, forum.purebasic.com 
Procedure.l hex2dec(h$)  ; h$ can be 0-FFFFFFF. 

  h$=UCase(h$)  
  For r=1 To Len(h$)    
    d<<4 : a$=Mid(h$,r,1)    
    If Asc(a$)>60      
      d+Asc(a$)-55    
    Else      
      d+Asc(a$)-48    
    EndIf  
  Next  
  
  ProcedureReturn d 

EndProcedure 

KeyInHex.s = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 

j=0 
For i=1 To Len(KeyInHex) Step 2 
  d=Hex2Dec(Mid(KeyInHex,i,2)) 
  Key\k[j]=d 
  j=j+1 
Next i  

InputInHex.s = "00112233445566778899aabbccddeeff"


j=0 
For i=1 To Len(InputInHex) Step 2 
  d=Hex2Dec(Mid(InputInHex,i,2)) 
  IB\IO[j]=d 
  j=j+1 
Next i 

 
AES_Gen_Tabs()
 
;--- 06 Main


KeyL = 256 : Debug "Fixed Key Length ("+Str(KeyL)+")"
OutKey   ("Key =                ",@Key,16)
OutBlock ("Input =              ",@IB)
RetVal = AES_Encrypt_Key256(@Key,@Ecx)
RetVal = AES_Encrypt(@Ib,@Ob,@Ecx)
OutBlock ("Encrypted Text = ",@Ob)
RetVal = AES_Decrypt_Key256(@Key,@Dcx)
RetVal = AES_Decrypt(@Ob,@Rb,@Dcx)
OutBlock ("Decrypted Text = ",@Rb)
 
End
Or both are wrong. At least Shanarra doesn't like either. :twisted:

Posted: Fri Aug 13, 2004 12:07 am
by newbie
I must admit I didn't see it.

At least now people can choose, and personally I like the Sec lib for the different functions to encrypt in 128/192/256bits and the fact that I don't have to init the AES tabs, but anyway, as you said, Shannara won't like either ;)

I think it's very good that the both libs used with a diffrent syntaxe give the same result, that proove that they aren't flawed :)

I'll post soon my code to use Sec lib to encrypt/decrypt data of any size (with a little modification it can probably apply to yours).

Posted: Fri Aug 13, 2004 12:25 am
by Max.²
newbie wrote:I must admit I didn't see it.

At least now people can choose, and personally I like the Sec lib for the different functions to encrypt in 128/192/256bits and the fact that I don't have to init the AES tabs, but anyway, as you said, Shannara won't like either ;)

I think it's very good that the both libs used with a diffrent syntaxe give the same result, that proove that they aren't flawed :)

I'll post soon my code to use Sec lib to encrypt/decrypt data of any size (with a little modification it can probably apply to yours).
The functions in my lib are

AES_Encrypt_Key / AES_Decrypt_Key
AES_Encrypt_Key128 / AES_Decrypt_Key128
AES_Encrypt_Key192 / AES_Decrypt_Key192
AES_Encrypt_Key256 /AES_Decrypt_Key256

with the first ones able to do any - non-standard - key lengths as well.

Using the AES_GenTabs() makes the lib a bit smaller.

Variable sized data is the same as with sec's lib - encrypt blocks and pad the last one (too bad that there are some methods to do this; so applications will suffer interoperability from this likely, except you implement any).

But granted, sec's lib is easier to use, so I will use it likely, too. :wink:

Hey, if we get a third one to provide an AES lib, we can provide NASA level security. 3 independently working calculations. :lol:

Edit: A speed test when encrypting/decrypting a file would be interesting!

Posted: Fri Aug 13, 2004 12:30 am
by newbie
Hey, if we get a third one to provide an AES lib, we can provide NASA level security. 3 independently working calculations. :lol:
Don't do that ! they will close the PB forum and site and will send Fred in jail
:wink:

Anyway do not rely on me to do such lib, I had so much difficulties to use the Lib, so create one... :roll:

EDIT : if one of you, the 'big boss" (;)) can take a look at SHA-1... it's here viewtopic.php?t=12057 :roll:

Posted: Fri Aug 13, 2004 5:08 am
by sec
New update: http://metawire.org/~sec/aesv1.zip .

Code: Select all

;Test from fips-197.pdf
;PLAINTEXT: 00112233445566778899aabbccddeeff
;KEY: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f

Procedure.s bytetohex(bb.l)
 hexnum.s = "0123456789abcdef"
 bb = bb & $FF
 ProcedureReturn PeekS(@hexnum+ (bb>>4),1) + PeekS(@hexnum+ (bb & $0F),1)
EndProcedure

plain.s=Space(16)
PokeB(@plain,0)
For i = 1 To 15
 PokeB(@plain+i, PeekB(@plain+i-1)+$11)
Next i

key.s = Space(32)
For i = 0 To 31
 PokeB(@key+i,i)
Next i

AES256Init(@key)

;For k = 0 To 3

AES256Encrypt(@plain) ; notice: plain/cipher is at same place

Debug "#####ciphertext#####"
For i = 0 To 15
 Debug bytetohex(PeekB(@plain+i))
Next i

AES256Decrypt(@plain) ; notice: plain/cipher is at same place

Debug "#####plaintext#####"
For i = 0 To 15
 Debug bytetohex(PeekB(@plain+i))
Next i
;Next k

;other functions included
;AES128/192Init(bufferkey) AES128/192Encrypt(buffer to encrypt)
;AES128/192Init(bufferkey) AES128/192Decrypt(buffer to encrypt)

Posted: Fri Aug 13, 2004 10:52 am
by Max.²
Sec,

I tried to do a speed comparison between our libs. Everything works fine when I use a loop of 100 000; with higher numbers, like 1 000 000 it compiles, but then crashes.

BTW, could we agree on a lib naming convention? Like AES_Sec & AES_Max?

Code: Select all

;Test from fips-197.pdf 
;PLAINTEXT: 00112233445566778899aabbccddeeff 
;KEY: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 

Procedure.s bytetohex(bb.l) 
hexnum.s = "0123456789abcdef" 
bb = bb & $FF 
ProcedureReturn PeekS(@hexnum+ (bb>>4),1) + PeekS(@hexnum+ (bb & $0F),1) 
EndProcedure 

plain.s=Space(16) 
PokeB(@plain,0) 
For i = 1 To 15 
PokeB(@plain+i, PeekB(@plain+i-1)+$11) 
Next i 

key.s = Space(32) 
For i = 0 To 31 
PokeB(@key+i,i) 
Next i 

Start=GetTickCount_()
For k=1 To 1000000
AES256Init(@key) 

;For k = 0 To 3 

AES256Encrypt(@plain) ; notice: plain/cipher is at same place 

; Debug "#####ciphertext#####" 
; For i = 0 To 15 
; Debug bytetohex(PeekB(@plain+i)) 
; Next i 

AES256Decrypt(@plain) ; notice: plain/cipher is at same place 
; 
;  Debug "#####plaintext#####" 
;  For i = 0 To 15 
;  Debug bytetohex(PeekB(@plain+i)) 
;  Next i 
Next k 

;other functions included 
;AES128/192Init(bufferkey) AES128/192Encrypt(buffer to encrypt) 
;AES128/192Init(bufferkey) AES128/192Decrypt(buffer to encrypt)
Debug GetTickCount_()-Start


;http://www.host4scripts.de/pub/AES.zip
AES_Gen_Tabs() 

;--- 06 Main 

Ecx.s = Space(255)
Ob.s = Space(255)
Rb.s = Space(255)

Start=GetTickCount_()
For k=1 To 1000000
RetVal = AES_Encrypt_Key256(@Key,@Ecx) 

RetVal = AES_Encrypt(@Plain,@Ob,@Ecx)

;  Debug "#####ciphertext#####" 
;  For i = 0 To 15 
;  Debug bytetohex(PeekB(@ob+i)) 
;  Next i 
 
RetVal = AES_Decrypt(@Ob,@Rb,@Ecx)  
;   Debug "#####plaintext#####" 
;   For i = 0 To 15 
;   Debug bytetohex(PeekB(@plain+i)) 
;   Next i 
Next k
Debug GetTickCount_()-Start

Posted: Fri Aug 13, 2004 11:31 am
by sec
Thank, i have a quick fix, to get http://metawire.org/~sec/aesv2.zip :)

And run this test:

Code: Select all

Procedure.s bytetohex(bb.l) 
hexnum.s = "0123456789abcdef" 
bb = bb & $FF 
ProcedureReturn PeekS(@hexnum+ (bb>>4),1) + PeekS(@hexnum+ (bb & $0F),1) 
EndProcedure 

plain.s=Space(16) 
PokeB(@plain,0) 
For i = 1 To 15 
PokeB(@plain+i, PeekB(@plain+i-1)+$11) 
Next i 

key.s = Space(32) 
For i = 0 To 31 
PokeB(@key+i,i) 
Next i 

Start=GetTickCount_() 
AES256Init(@key) 
For k=1 To 1000000 

;For k = 0 To 3 

AES256Encrypt(@plain) ; notice: plain/cipher is at same place 

; Debug "#####ciphertext#####" 
; For i = 0 To 15 
; Debug bytetohex(PeekB(@plain+i)) 
; Next i 

AES256Decrypt(@plain) ; notice: plain/cipher is at same place 
; 
;  Debug "#####plaintext#####" 
;  For i = 0 To 15 
;  Debug bytetohex(PeekB(@plain+i)) 
;  Next i 
Next k 
Debug GetTickCount_()-Start 


;http://www.host4scripts.de/pub/AES.zip 

;--- 06 Main 

Ecx.s = Space(255) 
Ob.s = Space(255) 
Rb.s = Space(255) 

Start=GetTickCount_() 
AES_Gen_Tabs() 
RetVal = AES_Encrypt_Key256(@Key,@Ecx) 

For k=1 To 1000000 

RetVal = AES_Encrypt(@Plain,@Ob,@Ecx) 

;   Debug "#####ciphertext#####" 
;   For i = 0 To 15 
;   Debug bytetohex(PeekB(@ob+i)) 
;   Next i 
; 
RetVal = AES_Decrypt(@Ob,@Rb,@Ecx)  
;    Debug "#####plaintext#####" 
;    For i = 0 To 15 
;    Debug bytetohex(PeekB(@plain+i)) 
;    Next i 
Next k 
Debug GetTickCount_()-Start 
On my machine , mine is abit faster :twisted:

Posted: Fri Aug 13, 2004 11:34 am
by newbie
Hi,

below a working code to use Sec's AES libv2 :

Code: Select all

;- Based on Sec's AES lib v2
;- August 13 2004 15H15 PM GMT+1 by newbie

AESkey.s = MD5Fingerprint("toto", 4) 
AES256Init(@AESkey)

Procedure Calculate_AES_Padding(*Buffer)
    Debug "PeekS(*Buffer) = " + PeekS(*Buffer)
    length_buff.l = GlobalSize_(*Buffer) ; buffer lenght
    Debug "length_buff 1 = " + Str(length_buff)
    bytes_remaining.l = length_buff % 16 ; length_buff modulo 16
    Debug "bytes_remaining = " + Str(bytes_remaining)
    padding.l = 16 - bytes_remaining
    Debug "padding = " + Str(padding)
    length_required.l = length_buff + padding
    Debug "length_required (after padding) = " + Str(length_required)
    
    ProcedureReturn length_required
    
EndProcedure

Procedure AESEncrypt(*Buffer)
    length_buff.l = GlobalSize_(*Buffer)
    
    a = 0
    While length_buff <> 0
        length_buff - 16
        AES256Encrypt(*Buffer + a)
        a + 16
    Wend
    
    ProcedureReturn *Buffer
EndProcedure

Procedure AESdecrypt(*Buffer)
   length_buff.l = GlobalSize_(*Buffer)
    
    a = 0
    While length_buff <> 0
        length_buff - 16
        AES256Decrypt(*Buffer + a)
        a + 16
    Wend
    
    ProcedureReturn *Buffer
EndProcedure


plain.s = "I am a fan of SEC now :-) lololoLOL" ; our plain text, 35 bytes

Debug "clear = " + plain                        
Debug "len(clear) = " + Str(Len(plain))

length_required.l = Calculate_AES_Padding(@plain); length required for the buffer
    
*cypher_text = AllocateMemory(length_required)  ; creating the buffer to the right input/output size
PokeS(*cypher_text, plain)     ; copying our plain text into the buffer
Debug "LEN *cypher_text = " + Str(Len(PeekS(*cypher_text)))

;-encryption
*cypher_text = AESEncrypt(*cypher_text)   ; encrypting our plain text

Debug "encrypted = " + PeekS(*cypher_text, length_required)
Debug "LEN encrypted = " + Str(Len(PeekS(*cypher_text, length_required)))

;- decryption
size.l = GlobalSize_(*cypher_text)
Debug "size = " + Str(size)
*plain_text = AllocateMemory(size)
CopyMemory(AESdecrypt(*cypher_text), *plain_text , size)

Debug "clear = " + PeekS(*plain_text, size);, length_required)
Debug "LEN clear = " + Str(Len(PeekS(*plain_text)))
Notice that the encryption/decryption functions will only work if you allocate the buffer before at the right size or else the GlobalSize_() will fail.
Notice too that the debug lines which use "Len(Peeks(*buffer))" are just unreliable information, you should not use it in the code involved to encrypt/decrypt or you will get in troubles. Indeed "Peeks()" can't get past the null bytes and will stop at the first null byte encounter, and will not read the entire encrypted text.


In special cases, when there is a null bytes in the middle of the encrypted string, and that you receive it via the network (e.g you didn't encrypt it, so you have no information about the size), and that GlobalSize_() fails and returns 0, then you might find usefull to use the following procedure :

Code: Select all

;- updated the August 13 (end of the day) to take in count the case where
the buffer submitted to the procedure is filled completly without any final null byte

Procedure GetMemSize(*Buffer, size.l)
    cnt.b = 0
    pos.l = 0
    chr.w = 0
    i.l   = 0
    While i < size
        chr = (PeekB(*Buffer+i) & $FF)
        If chr = 0     ; if 0 byte
            If cnt = 0 ; if pos not registered
                pos = i; register the position of the null byte
                cnt = 1
            EndIf
        Else           ; if not a 0 byte
            If cnt = 1 ; if pos registered
                cnt = 0; reset (last byte wasn't the last null byte)
            EndIf
        EndIf
        i + 1
    Wend
    
    If cnt = 0     ; no final null byte found
        pos = size ; the entire buffer is filled
    EndIf
    
    ProcedureReturn pos
    
EndProcedure
Give the buffer and the size of the buffer (size of the packet received)
and the procedure will return the size of the encrypted string within the packet. Let's say our packet size is 1024 bytes, and that only 80 bytes are filled, this function is the only way I found to calculate the size inside.

It might even be usefull to replace all of the GlobaSize_() above by this GetMemSize(), but I didn't try.

This code is may be perfectible, for now it has only be designed for text.
For files the GetMemSize() should work too.

I have spent hours just for this small piece of code, hope you'll enjoy, and thanks to our guru for the AES libs ;)

Posted: Fri Aug 13, 2004 11:42 am
by sec
Sorry, newbie. Is it ok now?

Posted: Fri Aug 13, 2004 11:44 am
by newbie
yes ;)

what are the modifications ? just to know :)

EDIT : I did the test, and here the results :

Sec's lib = 1281ms
Max's lib = 1578ms

of course those results are only for my computer :)

Posted: Fri Aug 13, 2004 11:47 am
by thefool
Hi :)

I was just wandering around the forum and i found this post, and i just wanted to ask:

Whats the best encryption? Aes or RC4?