Java tutorial
package org.bouncycastle.crypto.engines; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.KeyParameter; /** * an implementation of Rijndael, based on the documentation and reference implementation * by Paulo Barreto, Vincent Rijmen, for v2.0 August '99. * <p> * Note: this implementation is based on information prior to final NIST publication. */ public class RijndaelEngine implements BlockCipher { private static final int MAXROUNDS = 14; private static final int MAXKC = (256 / 4); private static final byte[] logtable = { (byte) 0, (byte) 0, (byte) 25, (byte) 1, (byte) 50, (byte) 2, (byte) 26, (byte) 198, (byte) 75, (byte) 199, (byte) 27, (byte) 104, (byte) 51, (byte) 238, (byte) 223, (byte) 3, (byte) 100, (byte) 4, (byte) 224, (byte) 14, (byte) 52, (byte) 141, (byte) 129, (byte) 239, (byte) 76, (byte) 113, (byte) 8, (byte) 200, (byte) 248, (byte) 105, (byte) 28, (byte) 193, (byte) 125, (byte) 194, (byte) 29, (byte) 181, (byte) 249, (byte) 185, (byte) 39, (byte) 106, (byte) 77, (byte) 228, (byte) 166, (byte) 114, (byte) 154, (byte) 201, (byte) 9, (byte) 120, (byte) 101, (byte) 47, (byte) 138, (byte) 5, (byte) 33, (byte) 15, (byte) 225, (byte) 36, (byte) 18, (byte) 240, (byte) 130, (byte) 69, (byte) 53, (byte) 147, (byte) 218, (byte) 142, (byte) 150, (byte) 143, (byte) 219, (byte) 189, (byte) 54, (byte) 208, (byte) 206, (byte) 148, (byte) 19, (byte) 92, (byte) 210, (byte) 241, (byte) 64, (byte) 70, (byte) 131, (byte) 56, (byte) 102, (byte) 221, (byte) 253, (byte) 48, (byte) 191, (byte) 6, (byte) 139, (byte) 98, (byte) 179, (byte) 37, (byte) 226, (byte) 152, (byte) 34, (byte) 136, (byte) 145, (byte) 16, (byte) 126, (byte) 110, (byte) 72, (byte) 195, (byte) 163, (byte) 182, (byte) 30, (byte) 66, (byte) 58, (byte) 107, (byte) 40, (byte) 84, (byte) 250, (byte) 133, (byte) 61, (byte) 186, (byte) 43, (byte) 121, (byte) 10, (byte) 21, (byte) 155, (byte) 159, (byte) 94, (byte) 202, (byte) 78, (byte) 212, (byte) 172, (byte) 229, (byte) 243, (byte) 115, (byte) 167, (byte) 87, (byte) 175, (byte) 88, (byte) 168, (byte) 80, (byte) 244, (byte) 234, (byte) 214, (byte) 116, (byte) 79, (byte) 174, (byte) 233, (byte) 213, (byte) 231, (byte) 230, (byte) 173, (byte) 232, (byte) 44, (byte) 215, (byte) 117, (byte) 122, (byte) 235, (byte) 22, (byte) 11, (byte) 245, (byte) 89, (byte) 203, (byte) 95, (byte) 176, (byte) 156, (byte) 169, (byte) 81, (byte) 160, (byte) 127, (byte) 12, (byte) 246, (byte) 111, (byte) 23, (byte) 196, (byte) 73, (byte) 236, (byte) 216, (byte) 67, (byte) 31, (byte) 45, (byte) 164, (byte) 118, (byte) 123, (byte) 183, (byte) 204, (byte) 187, (byte) 62, (byte) 90, (byte) 251, (byte) 96, (byte) 177, (byte) 134, (byte) 59, (byte) 82, (byte) 161, (byte) 108, (byte) 170, (byte) 85, (byte) 41, (byte) 157, (byte) 151, (byte) 178, (byte) 135, (byte) 144, (byte) 97, (byte) 190, (byte) 220, (byte) 252, (byte) 188, (byte) 149, (byte) 207, (byte) 205, (byte) 55, (byte) 63, (byte) 91, (byte) 209, (byte) 83, (byte) 57, (byte) 132, (byte) 60, (byte) 65, (byte) 162, (byte) 109, (byte) 71, (byte) 20, (byte) 42, (byte) 158, (byte) 93, (byte) 86, (byte) 242, (byte) 211, (byte) 171, (byte) 68, (byte) 17, (byte) 146, (byte) 217, (byte) 35, (byte) 32, (byte) 46, (byte) 137, (byte) 180, (byte) 124, (byte) 184, (byte) 38, (byte) 119, (byte) 153, (byte) 227, (byte) 165, (byte) 103, (byte) 74, (byte) 237, (byte) 222, (byte) 197, (byte) 49, (byte) 254, (byte) 24, (byte) 13, (byte) 99, (byte) 140, (byte) 128, (byte) 192, (byte) 247, (byte) 112, (byte) 7 }; private static final byte[] aLogtable = { (byte) 0, (byte) 3, (byte) 5, (byte) 15, (byte) 17, (byte) 51, (byte) 85, (byte) 255, (byte) 26, (byte) 46, (byte) 114, (byte) 150, (byte) 161, (byte) 248, (byte) 19, (byte) 53, (byte) 95, (byte) 225, (byte) 56, (byte) 72, (byte) 216, (byte) 115, (byte) 149, (byte) 164, (byte) 247, (byte) 2, (byte) 6, (byte) 10, (byte) 30, (byte) 34, (byte) 102, (byte) 170, (byte) 229, (byte) 52, (byte) 92, (byte) 228, (byte) 55, (byte) 89, (byte) 235, (byte) 38, (byte) 106, (byte) 190, (byte) 217, (byte) 112, (byte) 144, (byte) 171, (byte) 230, (byte) 49, (byte) 83, (byte) 245, (byte) 4, (byte) 12, (byte) 20, (byte) 60, (byte) 68, (byte) 204, (byte) 79, (byte) 209, (byte) 104, (byte) 184, (byte) 211, (byte) 110, (byte) 178, (byte) 205, (byte) 76, (byte) 212, (byte) 103, (byte) 169, (byte) 224, (byte) 59, (byte) 77, (byte) 215, (byte) 98, (byte) 166, (byte) 241, (byte) 8, (byte) 24, (byte) 40, (byte) 120, (byte) 136, (byte) 131, (byte) 158, (byte) 185, (byte) 208, (byte) 107, (byte) 189, (byte) 220, (byte) 127, (byte) 129, (byte) 152, (byte) 179, (byte) 206, (byte) 73, (byte) 219, (byte) 118, (byte) 154, (byte) 181, (byte) 196, (byte) 87, (byte) 249, (byte) 16, (byte) 48, (byte) 80, (byte) 240, (byte) 11, (byte) 29, (byte) 39, (byte) 105, (byte) 187, (byte) 214, (byte) 97, (byte) 163, (byte) 254, (byte) 25, (byte) 43, (byte) 125, (byte) 135, (byte) 146, (byte) 173, (byte) 236, (byte) 47, (byte) 113, (byte) 147, (byte) 174, (byte) 233, (byte) 32, (byte) 96, (byte) 160, (byte) 251, (byte) 22, (byte) 58, (byte) 78, (byte) 210, (byte) 109, (byte) 183, (byte) 194, (byte) 93, (byte) 231, (byte) 50, (byte) 86, (byte) 250, (byte) 21, (byte) 63, (byte) 65, (byte) 195, (byte) 94, (byte) 226, (byte) 61, (byte) 71, (byte) 201, (byte) 64, (byte) 192, (byte) 91, (byte) 237, (byte) 44, (byte) 116, (byte) 156, (byte) 191, (byte) 218, (byte) 117, (byte) 159, (byte) 186, (byte) 213, (byte) 100, (byte) 172, (byte) 239, (byte) 42, (byte) 126, (byte) 130, (byte) 157, (byte) 188, (byte) 223, (byte) 122, (byte) 142, (byte) 137, (byte) 128, (byte) 155, (byte) 182, (byte) 193, (byte) 88, (byte) 232, (byte) 35, (byte) 101, (byte) 175, (byte) 234, (byte) 37, (byte) 111, (byte) 177, (byte) 200, (byte) 67, (byte) 197, (byte) 84, (byte) 252, (byte) 31, (byte) 33, (byte) 99, (byte) 165, (byte) 244, (byte) 7, (byte) 9, (byte) 27, (byte) 45, (byte) 119, (byte) 153, (byte) 176, (byte) 203, (byte) 70, (byte) 202, (byte) 69, (byte) 207, (byte) 74, (byte) 222, (byte) 121, (byte) 139, (byte) 134, (byte) 145, (byte) 168, (byte) 227, (byte) 62, (byte) 66, (byte) 198, (byte) 81, (byte) 243, (byte) 14, (byte) 18, (byte) 54, (byte) 90, (byte) 238, (byte) 41, (byte) 123, (byte) 141, (byte) 140, (byte) 143, (byte) 138, (byte) 133, (byte) 148, (byte) 167, (byte) 242, (byte) 13, (byte) 23, (byte) 57, (byte) 75, (byte) 221, (byte) 124, (byte) 132, (byte) 151, (byte) 162, (byte) 253, (byte) 28, (byte) 36, (byte) 108, (byte) 180, (byte) 199, (byte) 82, (byte) 246, (byte) 1, (byte) 3, (byte) 5, (byte) 15, (byte) 17, (byte) 51, (byte) 85, (byte) 255, (byte) 26, (byte) 46, (byte) 114, (byte) 150, (byte) 161, (byte) 248, (byte) 19, (byte) 53, (byte) 95, (byte) 225, (byte) 56, (byte) 72, (byte) 216, (byte) 115, (byte) 149, (byte) 164, (byte) 247, (byte) 2, (byte) 6, (byte) 10, (byte) 30, (byte) 34, (byte) 102, (byte) 170, (byte) 229, (byte) 52, (byte) 92, (byte) 228, (byte) 55, (byte) 89, (byte) 235, (byte) 38, (byte) 106, (byte) 190, (byte) 217, (byte) 112, (byte) 144, (byte) 171, (byte) 230, (byte) 49, (byte) 83, (byte) 245, (byte) 4, (byte) 12, (byte) 20, (byte) 60, (byte) 68, (byte) 204, (byte) 79, (byte) 209, (byte) 104, (byte) 184, (byte) 211, (byte) 110, (byte) 178, (byte) 205, (byte) 76, (byte) 212, (byte) 103, (byte) 169, (byte) 224, (byte) 59, (byte) 77, (byte) 215, (byte) 98, (byte) 166, (byte) 241, (byte) 8, (byte) 24, (byte) 40, (byte) 120, (byte) 136, (byte) 131, (byte) 158, (byte) 185, (byte) 208, (byte) 107, (byte) 189, (byte) 220, (byte) 127, (byte) 129, (byte) 152, (byte) 179, (byte) 206, (byte) 73, (byte) 219, (byte) 118, (byte) 154, (byte) 181, (byte) 196, (byte) 87, (byte) 249, (byte) 16, (byte) 48, (byte) 80, (byte) 240, (byte) 11, (byte) 29, (byte) 39, (byte) 105, (byte) 187, (byte) 214, (byte) 97, (byte) 163, (byte) 254, (byte) 25, (byte) 43, (byte) 125, (byte) 135, (byte) 146, (byte) 173, (byte) 236, (byte) 47, (byte) 113, (byte) 147, (byte) 174, (byte) 233, (byte) 32, (byte) 96, (byte) 160, (byte) 251, (byte) 22, (byte) 58, (byte) 78, (byte) 210, (byte) 109, (byte) 183, (byte) 194, (byte) 93, (byte) 231, (byte) 50, (byte) 86, (byte) 250, (byte) 21, (byte) 63, (byte) 65, (byte) 195, (byte) 94, (byte) 226, (byte) 61, (byte) 71, (byte) 201, (byte) 64, (byte) 192, (byte) 91, (byte) 237, (byte) 44, (byte) 116, (byte) 156, (byte) 191, (byte) 218, (byte) 117, (byte) 159, (byte) 186, (byte) 213, (byte) 100, (byte) 172, (byte) 239, (byte) 42, (byte) 126, (byte) 130, (byte) 157, (byte) 188, (byte) 223, (byte) 122, (byte) 142, (byte) 137, (byte) 128, (byte) 155, (byte) 182, (byte) 193, (byte) 88, (byte) 232, (byte) 35, (byte) 101, (byte) 175, (byte) 234, (byte) 37, (byte) 111, (byte) 177, (byte) 200, (byte) 67, (byte) 197, (byte) 84, (byte) 252, (byte) 31, (byte) 33, (byte) 99, (byte) 165, (byte) 244, (byte) 7, (byte) 9, (byte) 27, (byte) 45, (byte) 119, (byte) 153, (byte) 176, (byte) 203, (byte) 70, (byte) 202, (byte) 69, (byte) 207, (byte) 74, (byte) 222, (byte) 121, (byte) 139, (byte) 134, (byte) 145, (byte) 168, (byte) 227, (byte) 62, (byte) 66, (byte) 198, (byte) 81, (byte) 243, (byte) 14, (byte) 18, (byte) 54, (byte) 90, (byte) 238, (byte) 41, (byte) 123, (byte) 141, (byte) 140, (byte) 143, (byte) 138, (byte) 133, (byte) 148, (byte) 167, (byte) 242, (byte) 13, (byte) 23, (byte) 57, (byte) 75, (byte) 221, (byte) 124, (byte) 132, (byte) 151, (byte) 162, (byte) 253, (byte) 28, (byte) 36, (byte) 108, (byte) 180, (byte) 199, (byte) 82, (byte) 246, (byte) 1, }; private static final byte[] S = { (byte) 99, (byte) 124, (byte) 119, (byte) 123, (byte) 242, (byte) 107, (byte) 111, (byte) 197, (byte) 48, (byte) 1, (byte) 103, (byte) 43, (byte) 254, (byte) 215, (byte) 171, (byte) 118, (byte) 202, (byte) 130, (byte) 201, (byte) 125, (byte) 250, (byte) 89, (byte) 71, (byte) 240, (byte) 173, (byte) 212, (byte) 162, (byte) 175, (byte) 156, (byte) 164, (byte) 114, (byte) 192, (byte) 183, (byte) 253, (byte) 147, (byte) 38, (byte) 54, (byte) 63, (byte) 247, (byte) 204, (byte) 52, (byte) 165, (byte) 229, (byte) 241, (byte) 113, (byte) 216, (byte) 49, (byte) 21, (byte) 4, (byte) 199, (byte) 35, (byte) 195, (byte) 24, (byte) 150, (byte) 5, (byte) 154, (byte) 7, (byte) 18, (byte) 128, (byte) 226, (byte) 235, (byte) 39, (byte) 178, (byte) 117, (byte) 9, (byte) 131, (byte) 44, (byte) 26, (byte) 27, (byte) 110, (byte) 90, (byte) 160, (byte) 82, (byte) 59, (byte) 214, (byte) 179, (byte) 41, (byte) 227, (byte) 47, (byte) 132, (byte) 83, (byte) 209, (byte) 0, (byte) 237, (byte) 32, (byte) 252, (byte) 177, (byte) 91, (byte) 106, (byte) 203, (byte) 190, (byte) 57, (byte) 74, (byte) 76, (byte) 88, (byte) 207, (byte) 208, (byte) 239, (byte) 170, (byte) 251, (byte) 67, (byte) 77, (byte) 51, (byte) 133, (byte) 69, (byte) 249, (byte) 2, (byte) 127, (byte) 80, (byte) 60, (byte) 159, (byte) 168, (byte) 81, (byte) 163, (byte) 64, (byte) 143, (byte) 146, (byte) 157, (byte) 56, (byte) 245, (byte) 188, (byte) 182, (byte) 218, (byte) 33, (byte) 16, (byte) 255, (byte) 243, (byte) 210, (byte) 205, (byte) 12, (byte) 19, (byte) 236, (byte) 95, (byte) 151, (byte) 68, (byte) 23, (byte) 196, (byte) 167, (byte) 126, (byte) 61, (byte) 100, (byte) 93, (byte) 25, (byte) 115, (byte) 96, (byte) 129, (byte) 79, (byte) 220, (byte) 34, (byte) 42, (byte) 144, (byte) 136, (byte) 70, (byte) 238, (byte) 184, (byte) 20, (byte) 222, (byte) 94, (byte) 11, (byte) 219, (byte) 224, (byte) 50, (byte) 58, (byte) 10, (byte) 73, (byte) 6, (byte) 36, (byte) 92, (byte) 194, (byte) 211, (byte) 172, (byte) 98, (byte) 145, (byte) 149, (byte) 228, (byte) 121, (byte) 231, (byte) 200, (byte) 55, (byte) 109, (byte) 141, (byte) 213, (byte) 78, (byte) 169, (byte) 108, (byte) 86, (byte) 244, (byte) 234, (byte) 101, (byte) 122, (byte) 174, (byte) 8, (byte) 186, (byte) 120, (byte) 37, (byte) 46, (byte) 28, (byte) 166, (byte) 180, (byte) 198, (byte) 232, (byte) 221, (byte) 116, (byte) 31, (byte) 75, (byte) 189, (byte) 139, (byte) 138, (byte) 112, (byte) 62, (byte) 181, (byte) 102, (byte) 72, (byte) 3, (byte) 246, (byte) 14, (byte) 97, (byte) 53, (byte) 87, (byte) 185, (byte) 134, (byte) 193, (byte) 29, (byte) 158, (byte) 225, (byte) 248, (byte) 152, (byte) 17, (byte) 105, (byte) 217, (byte) 142, (byte) 148, (byte) 155, (byte) 30, (byte) 135, (byte) 233, (byte) 206, (byte) 85, (byte) 40, (byte) 223, (byte) 140, (byte) 161, (byte) 137, (byte) 13, (byte) 191, (byte) 230, (byte) 66, (byte) 104, (byte) 65, (byte) 153, (byte) 45, (byte) 15, (byte) 176, (byte) 84, (byte) 187, (byte) 22, }; private static final byte[] Si = { (byte) 82, (byte) 9, (byte) 106, (byte) 213, (byte) 48, (byte) 54, (byte) 165, (byte) 56, (byte) 191, (byte) 64, (byte) 163, (byte) 158, (byte) 129, (byte) 243, (byte) 215, (byte) 251, (byte) 124, (byte) 227, (byte) 57, (byte) 130, (byte) 155, (byte) 47, (byte) 255, (byte) 135, (byte) 52, (byte) 142, (byte) 67, (byte) 68, (byte) 196, (byte) 222, (byte) 233, (byte) 203, (byte) 84, (byte) 123, (byte) 148, (byte) 50, (byte) 166, (byte) 194, (byte) 35, (byte) 61, (byte) 238, (byte) 76, (byte) 149, (byte) 11, (byte) 66, (byte) 250, (byte) 195, (byte) 78, (byte) 8, (byte) 46, (byte) 161, (byte) 102, (byte) 40, (byte) 217, (byte) 36, (byte) 178, (byte) 118, (byte) 91, (byte) 162, (byte) 73, (byte) 109, (byte) 139, (byte) 209, (byte) 37, (byte) 114, (byte) 248, (byte) 246, (byte) 100, (byte) 134, (byte) 104, (byte) 152, (byte) 22, (byte) 212, (byte) 164, (byte) 92, (byte) 204, (byte) 93, (byte) 101, (byte) 182, (byte) 146, (byte) 108, (byte) 112, (byte) 72, (byte) 80, (byte) 253, (byte) 237, (byte) 185, (byte) 218, (byte) 94, (byte) 21, (byte) 70, (byte) 87, (byte) 167, (byte) 141, (byte) 157, (byte) 132, (byte) 144, (byte) 216, (byte) 171, (byte) 0, (byte) 140, (byte) 188, (byte) 211, (byte) 10, (byte) 247, (byte) 228, (byte) 88, (byte) 5, (byte) 184, (byte) 179, (byte) 69, (byte) 6, (byte) 208, (byte) 44, (byte) 30, (byte) 143, (byte) 202, (byte) 63, (byte) 15, (byte) 2, (byte) 193, (byte) 175, (byte) 189, (byte) 3, (byte) 1, (byte) 19, (byte) 138, (byte) 107, (byte) 58, (byte) 145, (byte) 17, (byte) 65, (byte) 79, (byte) 103, (byte) 220, (byte) 234, (byte) 151, (byte) 242, (byte) 207, (byte) 206, (byte) 240, (byte) 180, (byte) 230, (byte) 115, (byte) 150, (byte) 172, (byte) 116, (byte) 34, (byte) 231, (byte) 173, (byte) 53, (byte) 133, (byte) 226, (byte) 249, (byte) 55, (byte) 232, (byte) 28, (byte) 117, (byte) 223, (byte) 110, (byte) 71, (byte) 241, (byte) 26, (byte) 113, (byte) 29, (byte) 41, (byte) 197, (byte) 137, (byte) 111, (byte) 183, (byte) 98, (byte) 14, (byte) 170, (byte) 24, (byte) 190, (byte) 27, (byte) 252, (byte) 86, (byte) 62, (byte) 75, (byte) 198, (byte) 210, (byte) 121, (byte) 32, (byte) 154, (byte) 219, (byte) 192, (byte) 254, (byte) 120, (byte) 205, (byte) 90, (byte) 244, (byte) 31, (byte) 221, (byte) 168, (byte) 51, (byte) 136, (byte) 7, (byte) 199, (byte) 49, (byte) 177, (byte) 18, (byte) 16, (byte) 89, (byte) 39, (byte) 128, (byte) 236, (byte) 95, (byte) 96, (byte) 81, (byte) 127, (byte) 169, (byte) 25, (byte) 181, (byte) 74, (byte) 13, (byte) 45, (byte) 229, (byte) 122, (byte) 159, (byte) 147, (byte) 201, (byte) 156, (byte) 239, (byte) 160, (byte) 224, (byte) 59, (byte) 77, (byte) 174, (byte) 42, (byte) 245, (byte) 176, (byte) 200, (byte) 235, (byte) 187, (byte) 60, (byte) 131, (byte) 83, (byte) 153, (byte) 97, (byte) 23, (byte) 43, (byte) 4, (byte) 126, (byte) 186, (byte) 119, (byte) 214, (byte) 38, (byte) 225, (byte) 105, (byte) 20, (byte) 99, (byte) 85, (byte) 33, (byte) 12, (byte) 125, }; private static final int[] rcon = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; static byte[][] shifts0 = { { 0, 8, 16, 24 }, { 0, 8, 16, 24 }, { 0, 8, 16, 24 }, { 0, 8, 16, 32 }, { 0, 8, 24, 32 } }; static byte[][] shifts1 = { { 0, 24, 16, 8 }, { 0, 32, 24, 16 }, { 0, 40, 32, 24 }, { 0, 48, 40, 24 }, { 0, 56, 40, 32 } }; /** * multiply two elements of GF(2^m) * needed for MixColumn and InvMixColumn */ private byte mul0x2(int b) { if (b != 0) { return aLogtable[25 + (logtable[b] & 0xff)]; } else { return 0; } } private byte mul0x3(int b) { if (b != 0) { return aLogtable[1 + (logtable[b] & 0xff)]; } else { return 0; } } private byte mul0x9(int b) { if (b >= 0) { return aLogtable[199 + b]; } else { return 0; } } private byte mul0xb(int b) { if (b >= 0) { return aLogtable[104 + b]; } else { return 0; } } private byte mul0xd(int b) { if (b >= 0) { return aLogtable[238 + b]; } else { return 0; } } private byte mul0xe(int b) { if (b >= 0) { return aLogtable[223 + b]; } else { return 0; } } /** * xor corresponding text input and round key input bytes */ private void KeyAddition(long[] rk) { A0 ^= rk[0]; A1 ^= rk[1]; A2 ^= rk[2]; A3 ^= rk[3]; } private long shift(long r, int shift) { return (((r >>> shift) | (r << (BC - shift)))) & BC_MASK; } /** * Row 0 remains unchanged * The other three rows are shifted a variable amount */ private void ShiftRow(byte[] shiftsSC) { A1 = shift(A1, shiftsSC[1]); A2 = shift(A2, shiftsSC[2]); A3 = shift(A3, shiftsSC[3]); } private long applyS(long r, byte[] box) { long res = 0; for (int j = 0; j < BC; j += 8) { res |= (long) (box[(int) ((r >> j) & 0xff)] & 0xff) << j; } return res; } /** * Replace every byte of the input by the byte at that place * in the nonlinear S-box */ private void Substitution(byte[] box) { A0 = applyS(A0, box); A1 = applyS(A1, box); A2 = applyS(A2, box); A3 = applyS(A3, box); } /** * Mix the bytes of every column in a linear way */ private void MixColumn() { long r0, r1, r2, r3; r0 = r1 = r2 = r3 = 0; for (int j = 0; j < BC; j += 8) { int a0 = (int) ((A0 >> j) & 0xff); int a1 = (int) ((A1 >> j) & 0xff); int a2 = (int) ((A2 >> j) & 0xff); int a3 = (int) ((A3 >> j) & 0xff); r0 |= (long) ((mul0x2(a0) ^ mul0x3(a1) ^ a2 ^ a3) & 0xff) << j; r1 |= (long) ((mul0x2(a1) ^ mul0x3(a2) ^ a3 ^ a0) & 0xff) << j; r2 |= (long) ((mul0x2(a2) ^ mul0x3(a3) ^ a0 ^ a1) & 0xff) << j; r3 |= (long) ((mul0x2(a3) ^ mul0x3(a0) ^ a1 ^ a2) & 0xff) << j; } A0 = r0; A1 = r1; A2 = r2; A3 = r3; } /** * Mix the bytes of every column in a linear way * This is the opposite operation of Mixcolumn */ private void InvMixColumn() { long r0, r1, r2, r3; r0 = r1 = r2 = r3 = 0; for (int j = 0; j < BC; j += 8) { int a0 = (int) ((A0 >> j) & 0xff); int a1 = (int) ((A1 >> j) & 0xff); int a2 = (int) ((A2 >> j) & 0xff); int a3 = (int) ((A3 >> j) & 0xff); // // pre-lookup the log table // a0 = (a0 != 0) ? (logtable[a0 & 0xff] & 0xff) : -1; a1 = (a1 != 0) ? (logtable[a1 & 0xff] & 0xff) : -1; a2 = (a2 != 0) ? (logtable[a2 & 0xff] & 0xff) : -1; a3 = (a3 != 0) ? (logtable[a3 & 0xff] & 0xff) : -1; r0 |= (long) ((mul0xe(a0) ^ mul0xb(a1) ^ mul0xd(a2) ^ mul0x9(a3)) & 0xff) << j; r1 |= (long) ((mul0xe(a1) ^ mul0xb(a2) ^ mul0xd(a3) ^ mul0x9(a0)) & 0xff) << j; r2 |= (long) ((mul0xe(a2) ^ mul0xb(a3) ^ mul0xd(a0) ^ mul0x9(a1)) & 0xff) << j; r3 |= (long) ((mul0xe(a3) ^ mul0xb(a0) ^ mul0xd(a1) ^ mul0x9(a2)) & 0xff) << j; } A0 = r0; A1 = r1; A2 = r2; A3 = r3; } /** * Calculate the necessary round keys * The number of calculations depends on keyBits and blockBits */ private long[][] generateWorkingKey(byte[] key) { int KC; int t, rconpointer = 0; int keyBits = key.length * 8; byte[][] tk = new byte[4][MAXKC]; long[][] W = new long[MAXROUNDS + 1][4]; switch (keyBits) { case 128: KC = 4; break; case 160: KC = 5; break; case 192: KC = 6; break; case 224: KC = 7; break; case 256: KC = 8; break; default: throw new IllegalArgumentException("Key length not 128/160/192/224/256 bits."); } if (keyBits >= blockBits) { ROUNDS = KC + 6; } else { ROUNDS = (BC / 8) + 6; } // // copy the key into the processing area // int index = 0; for (int i = 0; i < key.length; i++) { tk[i % 4][i / 4] = key[index++]; } t = 0; // // copy values into round key array // for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) { for (int i = 0; i < 4; i++) { W[t / (BC / 8)][i] |= (long) (tk[i][j] & 0xff) << ((t * 8) % BC); } } // // while not enough round key material calculated // calculate new values // while (t < (ROUNDS + 1) * (BC / 8)) { for (int i = 0; i < 4; i++) { tk[i][0] ^= S[tk[(i + 1) % 4][KC - 1] & 0xff]; } tk[0][0] ^= rcon[rconpointer++]; if (KC <= 6) { for (int j = 1; j < KC; j++) { for (int i = 0; i < 4; i++) { tk[i][j] ^= tk[i][j - 1]; } } } else { for (int j = 1; j < 4; j++) { for (int i = 0; i < 4; i++) { tk[i][j] ^= tk[i][j - 1]; } } for (int i = 0; i < 4; i++) { tk[i][4] ^= S[tk[i][3] & 0xff]; } for (int j = 5; j < KC; j++) { for (int i = 0; i < 4; i++) { tk[i][j] ^= tk[i][j - 1]; } } } // // copy values into round key array // for (int j = 0; (j < KC) && (t < (ROUNDS + 1) * (BC / 8)); j++, t++) { for (int i = 0; i < 4; i++) { W[t / (BC / 8)][i] |= (long) (tk[i][j] & 0xff) << ((t * 8) % (BC)); } } } return W; } private int BC; private long BC_MASK; private int ROUNDS; private int blockBits; private long[][] workingKey; private long A0, A1, A2, A3; private boolean forEncryption; private byte[] shifts0SC; private byte[] shifts1SC; /** * default constructor - 128 bit block size. */ public RijndaelEngine() { this(128); } /** * basic constructor - set the cipher up for a given blocksize * * @param blockBits the blocksize in bits, must be 128, 192, or 256. */ public RijndaelEngine(int blockBits) { switch (blockBits) { case 128: BC = 32; BC_MASK = 0xffffffffL; shifts0SC = shifts0[0]; shifts1SC = shifts1[0]; break; case 160: BC = 40; BC_MASK = 0xffffffffffL; shifts0SC = shifts0[1]; shifts1SC = shifts1[1]; break; case 192: BC = 48; BC_MASK = 0xffffffffffffL; shifts0SC = shifts0[2]; shifts1SC = shifts1[2]; break; case 224: BC = 56; BC_MASK = 0xffffffffffffffL; shifts0SC = shifts0[3]; shifts1SC = shifts1[3]; break; case 256: BC = 64; BC_MASK = 0xffffffffffffffffL; shifts0SC = shifts0[4]; shifts1SC = shifts1[4]; break; default: throw new IllegalArgumentException("unknown blocksize to Rijndael"); } this.blockBits = blockBits; } /** * initialise a Rijndael cipher. * * @param forEncryption whether or not we are for encryption. * @param params the parameters required to set up the cipher. * @exception IllegalArgumentException if the params argument is * inappropriate. */ public void init(boolean forEncryption, CipherParameters params) { if (params instanceof KeyParameter) { workingKey = generateWorkingKey(((KeyParameter) params).getKey()); this.forEncryption = forEncryption; return; } throw new IllegalArgumentException( "invalid parameter passed to Rijndael init - " + params.getClass().getName()); } public String getAlgorithmName() { return "Rijndael"; } public int getBlockSize() { return BC / 2; } public int processBlock(byte[] in, int inOff, byte[] out, int outOff) { if (workingKey == null) { throw new IllegalStateException("Rijndael engine not initialised"); } if ((inOff + (BC / 2)) > in.length) { throw new DataLengthException("input buffer too short"); } if ((outOff + (BC / 2)) > out.length) { throw new OutputLengthException("output buffer too short"); } if (forEncryption) { unpackBlock(in, inOff); encryptBlock(workingKey); packBlock(out, outOff); } else { unpackBlock(in, inOff); decryptBlock(workingKey); packBlock(out, outOff); } return BC / 2; } public void reset() { } private void unpackBlock(byte[] bytes, int off) { int index = off; A0 = (bytes[index++] & 0xff); A1 = (bytes[index++] & 0xff); A2 = (bytes[index++] & 0xff); A3 = (bytes[index++] & 0xff); for (int j = 8; j != BC; j += 8) { A0 |= (long) (bytes[index++] & 0xff) << j; A1 |= (long) (bytes[index++] & 0xff) << j; A2 |= (long) (bytes[index++] & 0xff) << j; A3 |= (long) (bytes[index++] & 0xff) << j; } } private void packBlock(byte[] bytes, int off) { int index = off; for (int j = 0; j != BC; j += 8) { bytes[index++] = (byte) (A0 >> j); bytes[index++] = (byte) (A1 >> j); bytes[index++] = (byte) (A2 >> j); bytes[index++] = (byte) (A3 >> j); } } private void encryptBlock(long[][] rk) { int r; // // begin with a key addition // KeyAddition(rk[0]); // // ROUNDS-1 ordinary rounds // for (r = 1; r < ROUNDS; r++) { Substitution(S); ShiftRow(shifts0SC); MixColumn(); KeyAddition(rk[r]); } // // Last round is special: there is no MixColumn // Substitution(S); ShiftRow(shifts0SC); KeyAddition(rk[ROUNDS]); } private void decryptBlock(long[][] rk) { int r; // To decrypt: apply the inverse operations of the encrypt routine, // in opposite order // // (KeyAddition is an involution: it 's equal to its inverse) // (the inverse of Substitution with table S is Substitution with the inverse table of S) // (the inverse of Shiftrow is Shiftrow over a suitable distance) // // First the special round: // without InvMixColumn // with extra KeyAddition // KeyAddition(rk[ROUNDS]); Substitution(Si); ShiftRow(shifts1SC); // // ROUNDS-1 ordinary rounds // for (r = ROUNDS - 1; r > 0; r--) { KeyAddition(rk[r]); InvMixColumn(); Substitution(Si); ShiftRow(shifts1SC); } // // End with the extra key addition // KeyAddition(rk[0]); } }