org.bouncycastle.crypto.engines.RijndaelEngine.java Source code

Java tutorial

Introduction

Here is the source code for org.bouncycastle.crypto.engines.RijndaelEngine.java

Source

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]);
    }
}