# Alle folgenden Funktionen sind genauso benannt wie im Skript. Sie verlangen jeweils als Eingabe eine 4X4-Matrix m deren # Eintraege Elemente aus dem Endlichen Koerper F2^28 sind. # Die Funktion HexToGF256 teilt einen gegebenen Hexadezimalstring der Laenge 32 in Hexadezimalstrings der Laenge 2 auf. Dann wird jeweils # jeder 2-Hexadezimalstring zu einem Polynom in w vom Grad <= 7. Dies ist analog zu der Aufteilung eines gegebenen 128-Bit-Strings # in 8-Bit-Strings. # Die 4x4-Matrix m soll Spaltenweise aufgefuellt werden, d.h. gibt der Aufruf von HexToGF256 die Liste [a1,a2,a3,a4,a5,a6,...] # zurueck, so besteht die erste Spalte von m aus [a1,a2,a3,a4], die zweite aus [a5,a6,...] usw. # AddRoundKey := function(m, kli) # #Verlangt als ersten Parameter die 4x4-Matrix m (Klartext) und als zweiten einen Schluessel aus dem Key-Schedule # return m + kli; end; phi := function(b) local k0x, x, k, z, f, g, h, res; k0x := PolynomialAlgebra(Parent(b)); AssignNames_(k0x, ["x"]); x := k0x.1; k := Parent(b); z := Generator(k); f := Element(k0x, List(b)); h := x^4 + x^3 + x^2 + x + 1; g := x^6 + x^5 + x + 1; res := (h * f + g) mod (x^8 + 1); res := Evaluate(res, z); return( res ); end; phiinv := function(b) local k0x, x, k, z, f, g, h, res; k0x := PolynomialAlgebra(Parent(b)); AssignNames_(k0x, ["x"]); x := k0x.1; k := Parent(b); z := Generator(k); f := Element(k0x, List(b)); h := x^6 + x^3 + x; g := x^2 + 1; res := (h * f + g) mod (x^8 + 1); res := Evaluate(res, z); return( res ); end; FieldInv := function(b) if b <> 0 then b := 1/b; fi; return( b); end; SubstBytes := function(m) local l; l := Apply([1..4], i->Apply([1..4], j->phi(FieldInv(m[i][j])))); l := Matrix( l); return( l ); end; SubstBytesInv := function(m) local l; l := Apply([1..4], i-> Apply([1..4], j->FieldInv(phiinv(m[i][j])))); l := Matrix( l); return( l ); end; ShiftRows := function(m) local l, i, j; l := [ [], [], [], [] ]; for i in [1..4] do for j in [1..4] do l[i][j] := m[i][(j + i - 2) mod 4 + 1]; od; od; l := Matrix( l); return( l ); end; ShiftRowsInv := function(m) local l, i, j; l := [ [], [], [], [] ]; for i in [1..4] do for j in [1..4] do l[i][j] := m[i][(j - i) mod 4 + 1]; od; od; l := Matrix( l); return( l ); end; MixColumns := function(m) local k, z, t; k := Parent(m[1][1]); z := Generator(k); t := [ [z, z+1, 1, 1], [1, z, z+1, 1], [1, 1, z, z+1], [z+1, 1, 1, z] ]; t := Matrix( t) ; return( t * Matrix(m) ); end; MixColumnsInv := function(m) local k, z, t; k := Parent(m[1][1]); z := Generator(k); t := [ [z, z+1, 1, 1], [1, z, z+1, 1], [1, 1, z, z+1], [z+1, 1, 1, z] ]; t := Matrix( t ); t := t^(-1); return( t * Matrix(m) ); end; ########################################################################## # # Key schdeule # SubstWord := function(w) local t, l; t := [ phi(FieldInv(w[1][1])), phi(FieldInv(w[1][2])), phi(FieldInv(w[1][3])), phi(FieldInv(w[1][4])) ]; t := Matrix( [t]); return( t ); end; RotWord := function(w) local t; t := [ w[1][2], w[1][3], w[1][4], w[1][1] ]; t := Matrix( [t]); return( t ); end; fff := function(j, w, b) # # Funktion f # local z; if j mod b = 0 then z := Generator(Parent(w[1][1])); return SubstWord(RotWord(w)) + Matrix([ [z^((Element(Integers(),j/b) - 1)), 0, 0, 0] ] ); elif b > 6 and j mod b = 4 then return SubstWord(w); else return w; fi; end; KeySchedule := function(K, b, n) # #Erzeugt die Liste der Schluessel k1 bis kn, wobei K der Schluessel ist. b und n sind so wie im Skript. # local j, w, kl; w := List([0..b-1], i-> Matrix([ [ K[i*4+1], K[i*4+2], K[i*4+3], K[i*4+4] ]] )); for j in [b..4*n+3] do w[j+1] := w[j-b+1] + fff(j, w[j-1+1], b); od; kl := Apply([0..n], i-> Matrix( Apply([ w[i*4+1], w[i*4+2], w[i*4+3], w[i*4+4] ], i-> List(i)) ) ); kl := Apply([0..n], i-> Transpose(kl[i+1])); return kl; end; HexToGF256 := function(s, k) # # Input: # s is a hexadecimal string of even length. # k is GF_256 = GF_2[z]. # Output: # is a list of bytes (e.g. "10" --> z^4) # local k0, k0x, x, f, k, z, trans, B, i; if not Length(s) mod 2 = 0 then return false; fi; # Remark: Do not create k here because for two invocations # we get isomoprhic but different k's and then adding of elements # doesn't work ... z := Generator(k); trans := function(c) local hb; if c = '0' then hb := 0*z; elif c = '1' then hb := 1 + 0*z; elif c = '2' then hb := z; elif c = '3' then hb := 1 + z; elif c = '4' then hb := z^2; elif c = '5' then hb := 1 + z^2; elif c = '6' then hb := z + z^2; elif c = '7' then hb := 1 + z + z^2; elif c = '8' then hb := z^3; elif c = '9' then hb := 1 + z^3; elif c = 'A' then hb := z + z^3; elif c = 'B' then hb := 1 + z + z^3; elif c = 'C' then hb := z^2 + z^3; elif c = 'D' then hb := 1 + z^2 + z^3; elif c = 'E' then hb := z + z^2 + z^3; elif c = 'F' then hb := 1 + z + z^2 + z^3; else return false; fi; return hb; end; B := []; for i in [1..Element(Integers(),Length(s)/2)] do B[i] := trans(s[2*i-1])*z^4 + trans(s[2*i]); od; return( B ); end; GF256ToHex := function(B) # # Inverse to HexToGF256. # local k0, k0x, x, trans, b, s, l1, l, l2; k0 := FiniteField(2,1); k0x := PolynomialAlgebra(k0); AssignNames_(k0x, ["x"]); x := k0x.1; trans := function(hb) local c; if hb = 0*x then c := '0'; elif hb = 1 + 0*x then c := '1'; elif hb = x then c := '2'; elif hb = 1 + x then c := '3'; elif hb = x^2 then c := '4'; elif hb = 1 + x^2 then c := '5'; elif hb = x + x^2 then c := '6'; elif hb = 1 + x + x^2 then c := '7'; elif hb = x^3 then c := '8'; elif hb = 1 + x^3 then c := '9'; elif hb = x + x^3 then c := 'A'; elif hb = 1 + x + x^3 then c := 'B'; elif hb = x^2 + x^3 then c := 'C'; elif hb = 1 + x^2 + x^3 then c := 'D'; elif hb = x + x^2 + x^3 then c := 'E'; elif hb = 1 + x + x^2 + x^3 then c := 'F'; else return false; fi; return c; end; s := []; for b in B do l := Element(k0x, List(b)); l1 := l mod x^4; l2 := (l - l1) / x^4; s := Append(s, [trans(l2)]); s := Append(s, [trans(l1)]); od; return( s ); end; AESEncipher := function(K, m) # Input: # m hexadecimal string of 128 bits # K hexadecimal string of 128 or 192 or 256 bits. # # Output: # c = hexdecimal string of 128 bit. local k0,k0x,x,f,k,m; # Set up the finite field. k0 := FiniteField(2,1); k0x := PolynomialAlgebra(k0); AssignNames_(k0x, ["x"]); x := k0x.1; f := x^8 + x^4 + x^3 + x + 1; k := Extension(k0,f); m := HexToGF256(m, k); K := HexToGF256(K, k); ### ..... end; AESDecipher := function(K, m) local k0, k0x, f, k,x; k0 := FiniteField(2,1); k0x := PolynomialAlgebra(k0); AssignNames_(k0x, ["x"]); x := k0x.1; f := x^8 + x^4 + x^3 + x + 1; k := Extension(k0,f); m := HexToGF256(m, k); K := HexToGF256(K, k); ### .... end; #AES-Vorgaben: Damit ihr wisst ob euer AES auch wirklich funktioniert: KEY1 := "00010203050607080A0B0C0D0F101112"; PT1 := "506812A45F08C889B97F5980038B8359"; CT1 := "D8F532538289EF7D06B506A4FD5BE9C9"; KEY2 := "14151617191A1B1C1E1F202123242526"; PT2 := "5C6D71CA30DE8B8B00549984D2EC7D4B"; CT2 := "59AB30F4D4EE6E4FF9907EF65B1FB68C"; KEY3 := "00010203050607080A0B0C0D0F10111214151617191A1B1C"; PT3 := "2D33EEF2C0430A8A9EBF45E809C40BB6"; CT3 := "DFF4945E0336DF4C1C56BC700EFF837F"; KEY4 := "1E1F20212324252628292A2B2D2E2F30323334353738393A"; PT4 := "6AA375D1FA155A61FB72353E0A5A8756"; CT4 := "B6FDDEF4752765E347D5D2DC196D1252"; KEY5 := "00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526"; PT5 := "834EADFCCAC7E1B30664B1ABA44815AB"; CT5 := "1946DABF6A03A2A2C3D0B05080AED6FC"; KEY6 := "28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E"; PT6 := "D9DC4DBA3021B05D67C0518F72B62BF1"; CT6 := "5ED301D747D3CC715445EBDEC62F2FB4"; KEYS := [ KEY1, KEY2, KEY3, KEY4, KEY5, KEY6 ]; PTS := [ PT1, PT2, PT3, PT4, PT5, PT6 ]; CTS := [ CT1, CT2, CT3, CT4, CT5, CT6 ];