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