AES.bi

Code: Select all

```
#pragma once
#include once "crt/string.bi"
extern "C"
#define _AES_H_
#ifndef CBC
#define CBC 1
#endif
#ifndef ECB
#define ECB 1
#endif
#ifndef CTR
#define CTR 1
#endif
#define AES_BLOCKLEN 16 ' Block length in bytes - AES is 128b block only
#if defined(AES256) and (AES256 = 1)
#define AES_KEYLEN 32
#define AES_keyExpSize 240
#elseif defined(AES192) and (AES192 = 1)
#define AES_KEYLEN 24
#define AES_keyExpSize 208
#else
#define AES_KEYLEN 16 ' Key length in bytes
#define AES_keyExpSize 176
#ifndef AES128
#define AES128 1
#endif
#if AES128 = 0
#define AES128 1
#endif
#endif
type AES_ctx
RoundKey(0 to AES_keyExpSize-1) as ubyte
#if (defined(CBC) and (CBC = 1)) or (defined(CTR) and (CTR = 1))
Iv(0 to AES_BLOCKLEN-1) as ubyte
#endif
end type
declare sub AES_init_ctx(byval ctx as AES_ctx ptr, byval key as const zstring ptr)
#if (defined(CBC) and (CBC = 1)) or (defined(CTR) and (CTR = 1))
declare sub AES_init_ctx_iv(byval ctx as AES_ctx ptr, byval key as const zstring ptr, byval iv as const zstring ptr)
declare sub AES_ctx_set_iv(byval ctx as AES_ctx ptr, byval iv as const zstring ptr)
#endif
#if defined(ECB) and (ECB = 1)
' buffer size is exactly AES_BLOCKLEN bytes;
' you need only AES_init_ctx as IV is not used in ECB
declare sub AES_ECB_encrypt(byval ctx as const AES_ctx ptr, byval buf as zstring ptr)
declare sub AES_ECB_decrypt(byval ctx as const AES_ctx ptr, byval buf as zstring ptr)
#endif
#if defined(CBC) and (CBC = 1)
' buffer size MUST be mutile of AES_BLOCKLEN;
' Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
' NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
' no IV should ever be reused with the same key
declare sub AES_CBC_encrypt_buffer(byval ctx as AES_ctx ptr, byval buf as zstring ptr, byval length as uinteger)
declare sub AES_CBC_decrypt_buffer(byval ctx as AES_ctx ptr, byval buf as zstring ptr, byval length as uinteger)
#endif
#if defined(CTR) and (CTR = 1)
' Same function for encrypting as for decrypting.
' IV is incremented for every block, and used after encryption as XOR-compliment for output
' Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
' NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
' no IV should ever be reused with the same key
declare sub AES_CTR_xcrypt_buffer(byval ctx as AES_ctx ptr, byval buf as zstring ptr, byval length as uinteger)
#endif
const Nb = 4
#if defined(AES256) and (AES256 = 1)
#define Nk 8
#define Nr 14
#elseif defined(AES192) and (AES192 = 1)
#define Nk 6
#define Nr 12
#else
#define Nk 4 ' The number of 32 bit words in a key.
#define Nr 10 ' The number of rounds in AES Cipher.
#endif
const MULTIPLY_AS_A_FUNCTION = 0
dim shared sbox(0 to 255) as const ubyte = {&h63, &h7c, &h77, &h7b, &hf2, &h6b, &h6f, &hc5, &h30, &h01, _
&h67, &h2b, &hfe, &hd7, &hab, &h76, &hca, &h82, &hc9, &h7d, &hfa, &h59, &h47, &hf0, &had, &hd4, &ha2, _
&haf, &h9c, &ha4, &h72, &hc0, &hb7, &hfd, &h93, &h26, &h36, &h3f, &hf7, &hcc, &h34, &ha5, &he5, &hf1, _
&h71, &hd8, &h31, &h15, &h04, &hc7, &h23, &hc3, &h18, &h96, &h05, &h9a, &h07, &h12, &h80, &he2, &heb, _
&h27, &hb2, &h75, &h09, &h83, &h2c, &h1a, &h1b, &h6e, &h5a, &ha0, &h52, &h3b, &hd6, &hb3, &h29, &he3, _
&h2f, &h84, &h53, &hd1, &h00, &hed, &h20, &hfc, &hb1, &h5b, &h6a, &hcb, &hbe, &h39, &h4a, &h4c, &h58, _
&hcf, &hd0, &hef, &haa, &hfb, &h43, &h4d, &h33, &h85, &h45, &hf9, &h02, &h7f, &h50, &h3c, &h9f, &ha8, _
&h51, &ha3, &h40, &h8f, &h92, &h9d, &h38, &hf5, &hbc, &hb6, &hda, &h21, &h10, &hff, &hf3, &hd2, &hcd, _
&h0c, &h13, &hec, &h5f, &h97, &h44, &h17, &hc4, &ha7, &h7e, &h3d, &h64, &h5d, &h19, &h73, &h60, &h81, _
&h4f, &hdc, &h22, &h2a, &h90, &h88, &h46, &hee, &hb8, &h14, &hde, &h5e, &h0b, &hdb, &he0, &h32, &h3a, _
&h0a, &h49, &h06, &h24, &h5c, &hc2, &hd3, &hac, &h62, &h91, &h95, &he4, &h79, &he7, &hc8, &h37, &h6d, _
&h8d, &hd5, &h4e, &ha9, &h6c, &h56, &hf4, &hea, &h65, &h7a, &hae, &h08, &hba, &h78, &h25, &h2e, &h1c, _
&ha6, &hb4, &hc6, &he8, &hdd, &h74, &h1f, &h4b, &hbd, &h8b, &h8a, &h70, &h3e, &hb5, &h66, &h48, &h03, _
&hf6, &h0e, &h61, &h35, &h57, &hb9, &h86, &hc1, &h1d, &h9e, &he1, &hf8, &h98, &h11, &h69, &hd9, &h8e, _
&h94, &h9b, &h1e, &h87, &he9, &hce, &h55, &h28, &hdf, &h8c, &ha1, &h89, &h0d, &hbf, &he6, &h42, &h68, _
&h41, &h99, &h2d, &h0f, &hb0, &h54, &hbb, &h16}
#if (defined(CBC) and CBC = 1) or (defined(ECB) and ECB = 1)
dim shared rsbox(0 to 255) as const ubyte = { _
&h52, &h09, &h6a, &hd5, &h30, &h36, &ha5, &h38, &hbf, &h40, &ha3, &h9e, &h81, &hf3, &hd7, &hfb, _
&h7c, &he3, &h39, &h82, &h9b, &h2f, &hff, &h87, &h34, &h8e, &h43, &h44, &hc4, &hde, &he9, &hcb, _
&h54, &h7b, &h94, &h32, &ha6, &hc2, &h23, &h3d, &hee, &h4c, &h95, &h0b, &h42, &hfa, &hc3, &h4e, _
&h08, &h2e, &ha1, &h66, &h28, &hd9, &h24, &hb2, &h76, &h5b, &ha2, &h49, &h6d, &h8b, &hd1, &h25, _
&h72, &hf8, &hf6, &h64, &h86, &h68, &h98, &h16, &hd4, &ha4, &h5c, &hcc, &h5d, &h65, &hb6, &h92, _
&h6c, &h70, &h48, &h50, &hfd, &hed, &hb9, &hda, &h5e, &h15, &h46, &h57, &ha7, &h8d, &h9d, &h84, _
&h90, &hd8, &hab, &h00, &h8c, &hbc, &hd3, &h0a, &hf7, &he4, &h58, &h05, &hb8, &hb3, &h45, &h06, _
&hd0, &h2c, &h1e, &h8f, &hca, &h3f, &h0f, &h02, &hc1, &haf, &hbd, &h03, &h01, &h13, &h8a, &h6b, _
&h3a, &h91, &h11, &h41, &h4f, &h67, &hdc, &hea, &h97, &hf2, &hcf, &hce, &hf0, &hb4, &he6, &h73, _
&h96, &hac, &h74, &h22, &he7, &had, &h35, &h85, &he2, &hf9, &h37, &he8, &h1c, &h75, &hdf, &h6e, _
&h47, &hf1, &h1a, &h71, &h1d, &h29, &hc5, &h89, &h6f, &hb7, &h62, &h0e, &haa, &h18, &hbe, &h1b, _
&hfc, &h56, &h3e, &h4b, &hc6, &hd2, &h79, &h20, &h9a, &hdb, &hc0, &hfe, &h78, &hcd, &h5a, &hf4, _
&h1f, &hdd, &ha8, &h33, &h88, &h07, &hc7, &h31, &hb1, &h12, &h10, &h59, &h27, &h80, &hec, &h5f, _
&h60, &h51, &h7f, &ha9, &h19, &hb5, &h4a, &h0d, &h2d, &he5, &h7a, &h9f, &h93, &hc9, &h9c, &hef, _
&ha0, &he0, &h3b, &h4d, &hae, &h2a, &hf5, &hb0, &hc8, &heb, &hbb, &h3c, &h83, &h53, &h99, &h61, _
&h17, &h2b, &h04, &h7e, &hba, &h77, &hd6, &h26, &he1, &h69, &h14, &h63, &h55, &h21, &h0c, &h7d }
#endif
dim shared Rcon(0 to 10) as const ubyte = {&h8d, &h01, &h02, &h04, &h08, &h10, &h20, &h40, &h80, &h1b, &h36}
#define getSBoxValue(num) sbox((num))
private sub KeyExpansion(byval RoundKey as ubyte ptr, byval Key as const ubyte ptr)
dim i as ulong
dim j as ulong
dim k as ulong
dim tempa(0 to 3) as ubyte
i = 0
while i < Nk
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)]
i += 1
wend
i = Nk
while i < (Nb * (Nr + 1))
scope
k = (i - 1) * 4
tempa(0) = RoundKey[(k + 0)]
tempa(1) = RoundKey[(k + 1)]
tempa(2) = RoundKey[(k + 2)]
tempa(3) = RoundKey[(k + 3)]
end scope
if (i mod Nk) = 0 then
scope
dim u8tmp as const ubyte = tempa(0)
tempa(0) = tempa(1)
tempa(1) = tempa(2)
tempa(2) = tempa(3)
tempa(3) = u8tmp
end scope
scope
tempa(0) = sbox(tempa(0))
tempa(1) = sbox(tempa(1))
tempa(2) = sbox(tempa(2))
tempa(3) = sbox(tempa(3))
end scope
tempa(0) = tempa(0) xor Rcon((i / Nk))
end if
#if defined(AES256) and (AES256 = 1)
if (i mod Nk = 4) then
' Function Subword()
scope
tempa(0) = getSBoxValue(tempa(0))
tempa(1) = getSBoxValue(tempa(1))
tempa(2) = getSBoxValue(tempa(2))
tempa(3) = getSBoxValue(tempa(3))
end scope
end if
#endif
j = i * 4
k = (i - Nk) * 4
RoundKey[(j + 0)] = RoundKey[(k + 0)] xor tempa(0)
RoundKey[(j + 1)] = RoundKey[(k + 1)] xor tempa(1)
RoundKey[(j + 2)] = RoundKey[(k + 2)] xor tempa(2)
RoundKey[(j + 3)] = RoundKey[(k + 3)] xor tempa(3)
i += 1
wend
end sub
private sub AES_init_ctx(byval ctx as AES_ctx ptr, byval key as const zstring ptr)
KeyExpansion(@(ctx->RoundKey(0)), key)
end sub
#if (defined(CBC) and (CBC = 1)) or (defined(CTR) and (CTR = 1))
sub AES_init_ctx_iv(byval ctx as AES_ctx ptr, byval key as const zstring ptr, byval iv as const zstring ptr)
KeyExpansion(@(ctx->RoundKey(0)), key)
memcpy (@(ctx->Iv(0)), iv, AES_BLOCKLEN)
end sub
sub AES_ctx_set_iv(byval ctx as AES_ctx ptr, byval iv as const zstring ptr)
memcpy (@(ctx->Iv(0)), iv, AES_BLOCKLEN)
end sub
#endif
private sub AddRoundKey(byval round as ubyte, byval state as ubyte ptr, byval RoundKey as const ubyte ptr)
dim i as ubyte
dim j as ubyte
i = 0
while i < 4
j = 0
while j < 4
state[i*4+j] xor= RoundKey[(round * Nb * 4) + (i * Nb) + j]
j += 1
wend
i += 1
wend
end sub
private sub SubBytes(byval state as ubyte ptr)
dim i as ubyte
dim j as ubyte
i = 0
while i < 4
j = 0
while j < 4
state[j*4+i] = sbox(state[j*4+i])
j += 1
wend
i += 1
wend
end sub
private sub ShiftRows(byval state as ubyte ptr)
dim temp as ubyte
temp = state[0*4+1]
state[0*4+1] = state[1*4+1]
state[1*4+1] = state[2*4+1]
state[2*4+1] = state[3*4+1]
state[3*4+1] = temp
temp = state[0*4+2]
state[0*4+2] = state[2*4+2]
state[2*4+2] = temp
temp = state[1*4+2]
state[1*4+2] = state[3*4+2]
state[3*4+2] = temp
temp = state[0*4+3]
state[0*4+3] = state[3*4+3]
state[3*4+3] = state[2*4+3]
state[2*4+3] = state[1*4+3]
state[1*4+3] = temp
end sub
private function xtime(byval x as ubyte) as ubyte
return (x shl 1) xor (((x shr 7) and 1) * &h1b)
end function
private sub MixColumns(byval state as ubyte ptr)
dim i as ubyte
dim Tmp as ubyte
dim Tm as ubyte
dim t as ubyte
i = 0
while i < 4
t = state[i*4+0]
Tmp = ((state[i*4+0] xor state[i*4+1]) xor state[i*4+2]) xor state[i*4+3]
Tm = state[i*4+0] xor state[i*4+1]
Tm = xtime(Tm)
state[i*4+0] xor= Tm xor Tmp
Tm = state[i*4+1] xor state[i*4+2]
Tm = xtime(Tm)
state[i*4+1] xor= Tm xor Tmp
Tm = state[i*4+2] xor state[i*4+3]
Tm = xtime(Tm)
state[i*4+2] xor= Tm xor Tmp
Tm = state[i*4+3] xor t
Tm = xtime(Tm)
state[i*4+3] xor= Tm xor Tmp
i += 1
wend
end sub
#if MULTIPLY_AS_A_FUNCTION
function Multiply(byval x as ubyte, byval y as ubyte) as ubyte
return (((y and 1) * x) xor _
((y shr 1 and 1) * xtime(x)) xor _
((y shr 2 and 1) * xtime(xtime(x))) xor _
((y shr 3 and 1) * xtime(xtime(xtime(x)))) xor _
((y shr 4 and 1) * xtime(xtime(xtime(xtime(x)))))) ' this last call to xtime() can be omitted
end function
#else
#define Multiply(x, y) ((((((y and 1) * x) xor (((y shr 1) and 1) * xtime(x))) xor (((y shr 2) and 1) * xtime(xtime(x)))) xor (((y shr 3) and 1) * xtime(xtime(xtime(x))))) xor (((y shr 4) and 1) * xtime(xtime(xtime(xtime(x))))))
#endif
#if (defined(CBC) and CBC = 1) or (defined(ECB) and ECB = 1)
/'
function getSBoxInvert(byval num as ubyte) as ubyte
return rsbox(num)
end function
'/
#define getSBoxInvert(num) (rsbox((num)))
' MixColumns function mixes the columns of the state matrix.
' The method used to multiply may be difficult to understand for the inexperienced.
' Please use the references to gain more information.
sub InvMixColumns(byval state as ubyte ptr)
dim as long i
dim as ubyte a, b, c, d
'for (i = 0; i < 4; ++i)
i = 0
while (i < 4)
a = state[i*4+0]
b = state[i*4+1]
c = state[i*4+2]
d = state[i*4+3]
state[i*4+0] = Multiply(a, &h0e) xor Multiply(b, &h0b) xor Multiply(c, &h0d) xor Multiply(d, &h09)
state[i*4+1] = Multiply(a, &h09) xor Multiply(b, &h0e) xor Multiply(c, &h0b) xor Multiply(d, &h0d)
state[i*4+2] = Multiply(a, &h0d) xor Multiply(b, &h09) xor Multiply(c, &h0e) xor Multiply(d, &h0b)
state[i*4+3] = Multiply(a, &h0b) xor Multiply(b, &h0d) xor Multiply(c, &h09) xor Multiply(d, &h0e)
i+=1
wend
end sub
' The SubBytes Function Substitutes the values in the
' state matrix with values in an S-box.
sub InvSubBytes(byval state as ubyte ptr)
dim as ubyte i, j
' for (i = 0; i < 4; ++i)
i = 0
while (i < 4)
' for (j = 0; j < 4; ++j)
j = 0
while (j < 4)
state[j*4+i] = getSBoxInvert(state[j*4+i])
j+=1
wend
i+=1
wend
end sub
sub InvShiftRows(byval state as ubyte ptr)
dim as ubyte temp
' Rotate first row 1 columns to right
temp = state[3*4+1]
state[3*4+1] = state[2*4+1]
state[2*4+1] = state[1*4+1]
state[1*4+1] = state[0*4+1]
state[0*4+1] = temp
' Rotate second row 2 columns to right
temp = state[0*4+2]
state[0*4+2] = state[2*4+2]
state[2*4+2] = temp
temp = state[1*4+2]
state[1*4+2] = state[3*4+2]
state[3*4+2] = temp
' Rotate third row 3 columns to right
temp = state[0*4+3]
state[0*4+3] = state[1*4+3]
state[1*4+3] = state[2*4+3]
state[2*4+3] = state[3*4+3]
state[3*4+3] = temp
end sub
#endif ' #if (defined(CBC) and CBC = 1) or (defined(ECB) and ECB = 1)
private sub Cipher(byval state as ubyte ptr, byval RoundKey as const ubyte ptr)
dim round as ubyte = 0
AddRoundKey(0, state, RoundKey)
round = 1
while 1
SubBytes(state)
ShiftRows(state)
if round = Nr then
exit while
end if
MixColumns(state)
AddRoundKey(round, state, RoundKey)
round += 1
wend
AddRoundKey(Nr, state, RoundKey)
end sub
#if (defined(CBC) and CBC = 1) or (defined(ECB) and ECB = 1)
sub InvCipher(byval state as ubyte ptr, byval RoundKey as const ubyte ptr)
dim as ubyte round = 0
' Add the First round key to the state before starting the rounds.
AddRoundKey(Nr, state, RoundKey)
' There will be Nr rounds.
' The first Nr-1 rounds are identical.
' These Nr rounds are executed in the loop below.
' Last one without InvMixColumn()
'for (round = (Nr - 1); ; --round)
round = (Nr - 1)
while 1
InvShiftRows(state)
InvSubBytes(state)
AddRoundKey(round, state, RoundKey)
if (round = 0) then
exit while
end if
InvMixColumns(state)
round -= 1
wend
end sub
#endif ' #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
/'*****************************************************************************'/
/'* Public functions: *'/
/'*****************************************************************************'/
#if defined(ECB) and (ECB = 1)
sub AES_ECB_encrypt(byval ctx as const AES_ctx ptr, byval buf as zstring ptr)
' The next function call encrypts the PlainText with the Key using AES algorithm.
Cipher(cptr(ubyte ptr, buf), @(ctx->RoundKey(0)))
end sub
sub AES_ECB_decrypt(byval ctx as const AES_ctx ptr, byval buf as zstring ptr)
' The next function call decrypts the PlainText with the Key using AES algorithm.
InvCipher(cptr(ubyte ptr, buf), @(ctx->RoundKey(0)))
end sub
#endif ' #if defined(ECB) and (ECB = 1)
#if defined(CBC) and (CBC = 1)
sub XorWithIv(byval buf as zstring ptr, byval Iv as const ubyte ptr)
dim as ubyte i
'for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size
i = 0
while (i < AES_BLOCKLEN)
buf[i] xor= Iv[i]
i+=1
wend
end sub
sub AES_CBC_encrypt_buffer(byval ctx as AES_ctx ptr, byval buf as zstring ptr, byval length as uinteger)
dim as uinteger i
dim as ubyte ptr Iv = @(ctx->Iv(0))
'for (i = 0; i < length; i += AES_BLOCKLEN)
i = 0
while (i < length)
XorWithIv(buf, Iv)
Cipher(cptr(ubyte ptr, buf), @(ctx->RoundKey(0)))
Iv = buf
buf += AES_BLOCKLEN
i += AES_BLOCKLEN
wend
' store Iv in ctx for next call
memcpy(@(ctx->Iv(0)), Iv, AES_BLOCKLEN)
end sub
sub AES_CBC_decrypt_buffer(byval ctx as AES_ctx ptr, byval buf as zstring ptr, byval length as uinteger)
dim as uinteger i
dim as ubyte storeNextIv(0 to AES_BLOCKLEN-1)
'for (i = 0; i < length; i += AES_BLOCKLEN)
i = 0
while (i < length)
memcpy(@storeNextIv(0), buf, AES_BLOCKLEN)
InvCipher(cptr(ubyte ptr, buf), @(ctx->RoundKey(0)))
XorWithIv(buf, @(ctx->Iv(0)))
memcpy(@(ctx->Iv(0)), @storeNextIv(0), AES_BLOCKLEN)
buf += AES_BLOCKLEN
i += AES_BLOCKLEN
wend
end sub
#endif ' #if defined(CBC) and (CBC = 1)
#if defined(CTR) and (CTR = 1)
' Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key
sub AES_CTR_xcrypt_buffer(byval ctx as AES_ctx ptr, byval buf as zstring ptr, byval length as uinteger)
dim as ubyte buffer(0 to AES_BLOCKLEN-1)
dim as uinteger i
dim as long bi
'for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
i = 0
bi = AES_BLOCKLEN
while (i < length)
if (bi = AES_BLOCKLEN) then ' we need to regen xor compliment in buffer
memcpy(@buffer(0), @(ctx->Iv(0)), AES_BLOCKLEN)
Cipher(cptr(ubyte ptr, @buffer(0)), @(ctx->RoundKey(0)))
' Increment Iv and handle overflow
'for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
bi = (AES_BLOCKLEN - 1)
while (bi >= 0)
' inc will overflow
if (ctx->Iv(bi) = 255) then
ctx->Iv(bi) = 0
bi-=1
continue while
end if
ctx->Iv(bi) += 1
exit while
wend
bi = 0
end if
buf[i] = (buf[i] xor buffer(bi))
i+=1
bi+=1
wend
end sub
#endif ' #if defined(CTR) and (CTR = 1)
end extern
```

Code: Select all

```
#define CBC 1
#define ECB 1
#define CTR 1
' set one of these to 1
#define AES128 0
#define AES192 0
#define AES256 1
#include "aes.bi"
dim as AES_ctx ctx
dim as zstring ptr buf=callocate(256)
dim as long length, i
*buf="3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"
length=len(*buf)
AES_init_ctx(@ctx, "123456789123456789")
'encrypt 16 bytes at a time
for i=0 to length step 16
AES_ECB_encrypt(@ctx, buf+i)
next
?*buf
'decrypt 16 bytes at a time
for i=0 to length step 16
AES_ECB_decrypt(@ctx, buf+i)
next
?*buf
deallocate(buf)
Sleep
```

note on the translation of (*state)[ i ][ j ], state is treated as a 4 x 4 matrix

state[i, j] won't work, instead I use state[i*4+j]