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