Skip to content

Commit 6d91bc8

Browse files
Merge pull request #169 from snatchysquid/aes-algorithm
Added implementation of AES algorithm
2 parents 0ee77e9 + f7793d4 commit 6d91bc8

File tree

1 file changed

+219
-0
lines changed

1 file changed

+219
-0
lines changed

AES_algo.java

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
public class AES {
2+
private static final byte[] sBox = new byte[] {
3+
0x63, 0x7c, 0x77, 0x7b, -0x0e, 0x6b, 0x6f, -0x3b, 0x30, 0x01, 0x67, 0x2b, -0x02, -0x29, -0x55, 0x76,
4+
-0x36, -0x7e, -0x37, 0x7d, -0x06, 0x59, 0x47, -0x10, -0x53, -0x2c, -0x5e, -0x51, -0x64, -0x5c, 0x72, -0x40,
5+
-0x49, -0x03, -0x6d, 0x26, 0x36, 0x3f, -0x09, -0x34, 0x34, -0x5b, -0x1b, -0x0f, 0x71, -0x28, 0x31, 0x15,
6+
0x04, -0x39, 0x23, -0x3d, 0x18, -0x6a, 0x05, -0x66, 0x07, 0x12, -0x80, -0x1e, -0x15, 0x27, -0x4e, 0x75,
7+
0x09, -0x7d, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, -0x60, 0x52, 0x3b, -0x2a, -0x4d, 0x29, -0x1d, 0x2f, -0x7c,
8+
0x53, -0x2f, 0x00, -0x13, 0x20, -0x04, -0x4f, 0x5b, 0x6a, -0x35, -0x42, 0x39, 0x4a, 0x4c, 0x58, -0x31,
9+
-0x30, -0x11, -0x56, -0x05, 0x43, 0x4d, 0x33, -0x7b, 0x45, -0x07, 0x02, 0x7f, 0x50, 0x3c, -0x61, -0x58,
10+
0x51, -0x5d, 0x40, -0x71, -0x6e, -0x63, 0x38, -0x0b, -0x44, -0x4a, -0x26, 0x21, 0x10, -0x01, -0x0d, -0x2e,
11+
-0x33, 0x0c, 0x13, -0x14, 0x5f, -0x69, 0x44, 0x17, -0x3c, -0x59, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
12+
0x60, -0x7f, 0x4f, -0x24, 0x22, 0x2a, -0x70, -0x78, 0x46, -0x12, -0x48, 0x14, -0x22, 0x5e, 0x0b, -0x25,
13+
-0x20, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, -0x3e, -0x2d, -0x54, 0x62, -0x6f, -0x6b, -0x1c, 0x79,
14+
-0x19, -0x38, 0x37, 0x6d, -0x73, -0x2b, 0x4e, -0x57, 0x6c, 0x56, -0x0c, -0x16, 0x65, 0x7a, -0x52, 0x08,
15+
-0x46, 0x78, 0x25, 0x2e, 0x1c, -0x5a, -0x4c, -0x3a, -0x18, -0x23, 0x74, 0x1f, 0x4b, -0x43, -0x75, -0x76,
16+
0x70, 0x3e, -0x4b, 0x66, 0x48, 0x03, -0x0a, 0x0e, 0x61, 0x35, 0x57, -0x47, -0x7a, -0x3f, 0x1d, -0x62,
17+
-0x1f, -0x08, -0x68, 0x11, 0x69, -0x27, -0x72, -0x6c, -0x65, 0x1e, -0x79, -0x17, -0x32, 0x55, 0x28, -0x21,
18+
-0x74, -0x5f, -0x77, 0x0d, -0x41, -0x1a, 0x42, 0x68, 0x41, -0x67, 0x2d, 0x0f, -0x50, 0x54, -0x45, 0x16
19+
};
20+
private static final int NB = 4;
21+
private static final int NK = 4;
22+
private static final int NR = 10;
23+
24+
private static final byte[] rCon = new byte[] {
25+
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, -0x80, 0x1b, 0x36
26+
};
27+
public byte[] key = new byte[4*NK];
28+
public byte[][] state = new byte[4][NB];
29+
public byte[][] keySchedule = new byte[NR+1][NB*4];
30+
31+
public AES(String stringKey) {
32+
if (stringKey.length() == NK*8) {
33+
this.key = hexStringToBytes(stringKey);
34+
}
35+
}
36+
private static byte[] hexStringToBytes(String key) {
37+
byte[] bytesKey = new byte[NK * 4];
38+
for (int i = 0; i < 4 * NK; i++) {
39+
bytesKey[i] = (byte) Integer.parseInt(key.substring(2 * i, 2 * (i + 1)), 16);
40+
}
41+
return bytesKey;
42+
}
43+
public void setKey(String stringKey) {
44+
if (stringKey.length() == NK*8) {
45+
this.key = hexStringToBytes(stringKey);
46+
}
47+
}
48+
/**
49+
* returns string of ciphertext
50+
* @param plainText text to encrypt
51+
* @return ciphertext
52+
*/
53+
public String encrypt(String plainText) {
54+
if (plainText.length() != 8 * NB || key.length != 4 * NK) {
55+
return null;
56+
}
57+
byte[] bytePlainText = hexStringToBytes(plainText);
58+
// place plaintext in state array
59+
for (int r = 0; r < 4; r++) {
60+
for (int c = 0; c < NB; c++) {
61+
state[r][c] = bytePlainText[4 * c + r];
62+
}
63+
}
64+
keyExpansion();
65+
addRoundKey(0); // round 0
66+
for (int round = 1; round < NR; round++) {
67+
subBytes();
68+
shiftRows();
69+
mixColumns();
70+
addRoundKey(round);
71+
}
72+
subBytes();
73+
shiftRows();
74+
addRoundKey(10);
75+
return stateToOutput(state);
76+
}
77+
/**
78+
* coverts state array to output string
79+
* @param bytes state array
80+
* @return bytes of state array ordered into a string
81+
*/
82+
private String stateToOutput(byte[][] bytes) {
83+
StringBuilder res = new StringBuilder();
84+
for (int c = 0; c < NB; c++) {
85+
for (int r = 0; r < 4; r++) {
86+
String sB = Integer.toString(bytes[r][c] & 0xff, 16);
87+
res.append(sB.length() == 1 ? '0' + sB : sB);
88+
}
89+
}
90+
return res.toString();
91+
}
92+
/**
93+
* XORes the state with the appropriate words from the key schedule
94+
* @param round current round to choose which word to use
95+
*/
96+
public void addRoundKey(int round) {
97+
98+
for (int r = 0; r < 4; r++) {
99+
for (int c = 0; c < NB; c++) {
100+
state[r][c] ^= keySchedule[round][4 * c + r];
101+
}
102+
}
103+
}
104+
/**
105+
* creates key schedule for the algorithm from encryption key
106+
*/
107+
public void keyExpansion() {
108+
System.arraycopy(key, 0, keySchedule[0], 0, 4*NK); // copy key into first indices of key schedule
109+
for (int i = NK; i < NB * (NR + 1); i++) {
110+
byte[] previousWord = new byte[4], temp;
111+
System.arraycopy(keySchedule[(i - 1) / NK], 4 * ((i - 1) % NK), previousWord, 0, 4);
112+
if (i % NK == 0) {
113+
temp = subWord(rotateWord(previousWord));
114+
temp[0] ^= rCon[i / NK - 1]; // xor with the rConstant
115+
} else {
116+
temp = previousWord;
117+
}
118+
// copy the new word into the key schedule
119+
for (int j = 0; j < 4; j++) {
120+
keySchedule[i / NK][4 * (i % 4) + j] = (byte) (keySchedule[i / NK - 1][4 * (i % 4) + j] ^ temp[j]);
121+
}
122+
}
123+
}
124+
/**
125+
* passes word through sBox for keyExpansion
126+
* @param word word to sBox
127+
* @return sBoxed word
128+
*/
129+
private static byte[] subWord(byte[] word) {
130+
byte[] subbedWord = new byte[4];
131+
for (int i = 0; i < 4; i++) {
132+
subbedWord[i] = sBox[word[i] & 0xff];
133+
}
134+
return subbedWord;
135+
}
136+
/**
137+
* rotates the word by one byte to the left
138+
* @param word word to rotate
139+
* @return rotate word
140+
*/
141+
public byte[] rotateWord(byte[] word) {
142+
byte[] shiftedWord = new byte[4];
143+
for (int i = 0; i < 4; i++) {
144+
shiftedWord[i] = word[(i + 1) % 4];
145+
}
146+
return shiftedWord;
147+
}
148+
/**
149+
* applies mixColumns operation on state array
150+
*/
151+
public void mixColumns() {
152+
for (int c = 0; c < NB; c++) {
153+
byte[] tempColumn = new byte[4];
154+
// first preform operation on temp array so not to overwrite the original needed values
155+
for (int r = 0; r < 4; r++) {
156+
tempColumn[r] = mixColumnsHelper(r, c);
157+
}
158+
159+
for (int r = 0; r < 4; r++) {
160+
state[r][c] = tempColumn[r];
161+
}
162+
}
163+
}
164+
/**
165+
* returns XOR operation needed for mixColumns
166+
* @param r row of byte
167+
* @param c column of byte
168+
* @return new value for byte in state array
169+
*/
170+
public byte mixColumnsHelper(int r, int c) {
171+
return (byte) (multiplyBy02(state[r][c])
172+
^ multiplyBy03(state[(r + 1) % 4][c])
173+
^ state[(r + 2) % 4][c]
174+
^ state[(r + 3) % 4][c]);
175+
}
176+
177+
/**
178+
* preforms multiplication by two in GF(2^8)
179+
* @param val value to multiply with
180+
* @return product
181+
*/
182+
public byte multiplyBy02(byte val) {
183+
return (byte) ((val << 1) ^ ((val & 0x80) == 0x00 ? 0x00 : 0x11b));
184+
}
185+
186+
public byte multiplyBy03(byte i) {
187+
// 3 * z = 2 * z + 1 * z
188+
return (byte) (multiplyBy02(i) ^ i);
189+
}
190+
191+
/**
192+
* applies the shiftRows operation on the state array
193+
*/
194+
public void shiftRows() {
195+
for (int r = 1; r < 4; r++) {
196+
byte[] tempRow = new byte[NB];
197+
System.arraycopy(state[r], 0, tempRow, 0, NB);
198+
for (int c = 0; c < NB; c++) {
199+
state[r][c] = tempRow[(r + c) % NB];
200+
}
201+
}
202+
}
203+
204+
/**
205+
* preforms the sBox operation on the state array
206+
*/
207+
public void subBytes() {
208+
for (int r = 0; r < NB; r++) {
209+
for (int c = 0; c < NB; c++) {
210+
state[r][c] = sBox[state[r][c] & 0xff];
211+
}
212+
}
213+
}
214+
215+
public static void main(String[] args) {
216+
AES aes = new AES("2b7e151628aed2a6abf7158809cf4f3c");
217+
System.out.println("Cipher Text: " + aes.encrypt("3243f6a8885a308d313198a2e0370734"));
218+
}
219+
}

0 commit comments

Comments
 (0)