All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pengrad.telegrambot.passport.decrypt.Aes256Cbc Maven / Gradle / Ivy

There is a newer version: 7.2.1
Show newest version
package com.pengrad.telegrambot.passport.decrypt;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Stas Parshin
 * 31 July 2018
 */
class Aes256Cbc {

    private final Cbc cbc;
    private final ByteArrayOutputStream baos;

    public Aes256Cbc(byte[] key, byte[] iv) {
        baos = new ByteArrayOutputStream();
        cbc = new Cbc(iv, key, baos);
    }

    public byte[] decrypt(byte[] data) throws Exception {
        cbc.decrypt(data);
        cbc.finishDecryption();
        return baos.toByteArray();
    }

    static final class Aes256 {

        /**
         * Number of {@code byte}s needed for 32 bit words.
         */
        private static final int WORD_SIZE = 4;

        /**
         * Number of {@code byte}s for a data block. The size is identical to the size of the internal
         * state, that is needed in encryption or decryption.
         * 

* The state can be viewed as a square matrix, modeled as a list of column vectors. *

*/ private static final int BLOCK_SIZE = 16; /** * key size in {@code byte}s */ private static final int KEY_SIZE = 32; /** * number of rounds */ private static final int ROUNDS = 14; /** * Size of the expanded key. For each round a {@code BLOCK_SIZE} block will be needed. Before * the first round another block will be needed. */ private static final int EXPANDED_KEY_SIZE = (ROUNDS + 1) * BLOCK_SIZE; /** * expanded key */ private final byte[] _expandedKey; /** * state needed between rounds in en- or decryption */ private final byte[] _tmp; /** * Permutation of {@code byte}s. The s-box permutation was specified in the reference document. */ private final byte[] _sBox = {(byte) 0x63, (byte) 0x7c, (byte) 0x77, (byte) 0x7b, (byte) 0xf2, (byte) 0x6b, (byte) 0x6f, (byte) 0xc5, (byte) 0x30, (byte) 0x01, (byte) 0x67, (byte) 0x2b, (byte) 0xfe, (byte) 0xd7, (byte) 0xab, (byte) 0x76, (byte) 0xca, (byte) 0x82, (byte) 0xc9, (byte) 0x7d, (byte) 0xfa, (byte) 0x59, (byte) 0x47, (byte) 0xf0, (byte) 0xad, (byte) 0xd4, (byte) 0xa2, (byte) 0xaf, (byte) 0x9c, (byte) 0xa4, (byte) 0x72, (byte) 0xc0, (byte) 0xb7, (byte) 0xfd, (byte) 0x93, (byte) 0x26, (byte) 0x36, (byte) 0x3f, (byte) 0xf7, (byte) 0xcc, (byte) 0x34, (byte) 0xa5, (byte) 0xe5, (byte) 0xf1, (byte) 0x71, (byte) 0xd8, (byte) 0x31, (byte) 0x15, (byte) 0x04, (byte) 0xc7, (byte) 0x23, (byte) 0xc3, (byte) 0x18, (byte) 0x96, (byte) 0x05, (byte) 0x9a, (byte) 0x07, (byte) 0x12, (byte) 0x80, (byte) 0xe2, (byte) 0xeb, (byte) 0x27, (byte) 0xb2, (byte) 0x75, (byte) 0x09, (byte) 0x83, (byte) 0x2c, (byte) 0x1a, (byte) 0x1b, (byte) 0x6e, (byte) 0x5a, (byte) 0xa0, (byte) 0x52, (byte) 0x3b, (byte) 0xd6, (byte) 0xb3, (byte) 0x29, (byte) 0xe3, (byte) 0x2f, (byte) 0x84, (byte) 0x53, (byte) 0xd1, (byte) 0x00, (byte) 0xed, (byte) 0x20, (byte) 0xfc, (byte) 0xb1, (byte) 0x5b, (byte) 0x6a, (byte) 0xcb, (byte) 0xbe, (byte) 0x39, (byte) 0x4a, (byte) 0x4c, (byte) 0x58, (byte) 0xcf, (byte) 0xd0, (byte) 0xef, (byte) 0xaa, (byte) 0xfb, (byte) 0x43, (byte) 0x4d, (byte) 0x33, (byte) 0x85, (byte) 0x45, (byte) 0xf9, (byte) 0x02, (byte) 0x7f, (byte) 0x50, (byte) 0x3c, (byte) 0x9f, (byte) 0xa8, (byte) 0x51, (byte) 0xa3, (byte) 0x40, (byte) 0x8f, (byte) 0x92, (byte) 0x9d, (byte) 0x38, (byte) 0xf5, (byte) 0xbc, (byte) 0xb6, (byte) 0xda, (byte) 0x21, (byte) 0x10, (byte) 0xff, (byte) 0xf3, (byte) 0xd2, (byte) 0xcd, (byte) 0x0c, (byte) 0x13, (byte) 0xec, (byte) 0x5f, (byte) 0x97, (byte) 0x44, (byte) 0x17, (byte) 0xc4, (byte) 0xa7, (byte) 0x7e, (byte) 0x3d, (byte) 0x64, (byte) 0x5d, (byte) 0x19, (byte) 0x73, (byte) 0x60, (byte) 0x81, (byte) 0x4f, (byte) 0xdc, (byte) 0x22, (byte) 0x2a, (byte) 0x90, (byte) 0x88, (byte) 0x46, (byte) 0xee, (byte) 0xb8, (byte) 0x14, (byte) 0xde, (byte) 0x5e, (byte) 0x0b, (byte) 0xdb, (byte) 0xe0, (byte) 0x32, (byte) 0x3a, (byte) 0x0a, (byte) 0x49, (byte) 0x06, (byte) 0x24, (byte) 0x5c, (byte) 0xc2, (byte) 0xd3, (byte) 0xac, (byte) 0x62, (byte) 0x91, (byte) 0x95, (byte) 0xe4, (byte) 0x79, (byte) 0xe7, (byte) 0xc8, (byte) 0x37, (byte) 0x6d, (byte) 0x8d, (byte) 0xd5, (byte) 0x4e, (byte) 0xa9, (byte) 0x6c, (byte) 0x56, (byte) 0xf4, (byte) 0xea, (byte) 0x65, (byte) 0x7a, (byte) 0xae, (byte) 0x08, (byte) 0xba, (byte) 0x78, (byte) 0x25, (byte) 0x2e, (byte) 0x1c, (byte) 0xa6, (byte) 0xb4, (byte) 0xc6, (byte) 0xe8, (byte) 0xdd, (byte) 0x74, (byte) 0x1f, (byte) 0x4b, (byte) 0xbd, (byte) 0x8b, (byte) 0x8a, (byte) 0x70, (byte) 0x3e, (byte) 0xb5, (byte) 0x66, (byte) 0x48, (byte) 0x03, (byte) 0xf6, (byte) 0x0e, (byte) 0x61, (byte) 0x35, (byte) 0x57, (byte) 0xb9, (byte) 0x86, (byte) 0xc1, (byte) 0x1d, (byte) 0x9e, (byte) 0xe1, (byte) 0xf8, (byte) 0x98, (byte) 0x11, (byte) 0x69, (byte) 0xd9, (byte) 0x8e, (byte) 0x94, (byte) 0x9b, (byte) 0x1e, (byte) 0x87, (byte) 0xe9, (byte) 0xce, (byte) 0x55, (byte) 0x28, (byte) 0xdf, (byte) 0x8c, (byte) 0xa1, (byte) 0x89, (byte) 0x0d, (byte) 0xbf, (byte) 0xe6, (byte) 0x42, (byte) 0x68, (byte) 0x41, (byte) 0x99, (byte) 0x2d, (byte) 0x0f, (byte) 0xb0, (byte) 0x54, (byte) 0xbb, (byte) 0x16}; /** * Inverse of the s-box permutation. */ private final byte[] _invSBox = {(byte) 0x52, (byte) 0x09, (byte) 0x6a, (byte) 0xd5, (byte) 0x30, (byte) 0x36, (byte) 0xa5, (byte) 0x38, (byte) 0xbf, (byte) 0x40, (byte) 0xa3, (byte) 0x9e, (byte) 0x81, (byte) 0xf3, (byte) 0xd7, (byte) 0xfb, (byte) 0x7c, (byte) 0xe3, (byte) 0x39, (byte) 0x82, (byte) 0x9b, (byte) 0x2f, (byte) 0xff, (byte) 0x87, (byte) 0x34, (byte) 0x8e, (byte) 0x43, (byte) 0x44, (byte) 0xc4, (byte) 0xde, (byte) 0xe9, (byte) 0xcb, (byte) 0x54, (byte) 0x7b, (byte) 0x94, (byte) 0x32, (byte) 0xa6, (byte) 0xc2, (byte) 0x23, (byte) 0x3d, (byte) 0xee, (byte) 0x4c, (byte) 0x95, (byte) 0x0b, (byte) 0x42, (byte) 0xfa, (byte) 0xc3, (byte) 0x4e, (byte) 0x08, (byte) 0x2e, (byte) 0xa1, (byte) 0x66, (byte) 0x28, (byte) 0xd9, (byte) 0x24, (byte) 0xb2, (byte) 0x76, (byte) 0x5b, (byte) 0xa2, (byte) 0x49, (byte) 0x6d, (byte) 0x8b, (byte) 0xd1, (byte) 0x25, (byte) 0x72, (byte) 0xf8, (byte) 0xf6, (byte) 0x64, (byte) 0x86, (byte) 0x68, (byte) 0x98, (byte) 0x16, (byte) 0xd4, (byte) 0xa4, (byte) 0x5c, (byte) 0xcc, (byte) 0x5d, (byte) 0x65, (byte) 0xb6, (byte) 0x92, (byte) 0x6c, (byte) 0x70, (byte) 0x48, (byte) 0x50, (byte) 0xfd, (byte) 0xed, (byte) 0xb9, (byte) 0xda, (byte) 0x5e, (byte) 0x15, (byte) 0x46, (byte) 0x57, (byte) 0xa7, (byte) 0x8d, (byte) 0x9d, (byte) 0x84, (byte) 0x90, (byte) 0xd8, (byte) 0xab, (byte) 0x00, (byte) 0x8c, (byte) 0xbc, (byte) 0xd3, (byte) 0x0a, (byte) 0xf7, (byte) 0xe4, (byte) 0x58, (byte) 0x05, (byte) 0xb8, (byte) 0xb3, (byte) 0x45, (byte) 0x06, (byte) 0xd0, (byte) 0x2c, (byte) 0x1e, (byte) 0x8f, (byte) 0xca, (byte) 0x3f, (byte) 0x0f, (byte) 0x02, (byte) 0xc1, (byte) 0xaf, (byte) 0xbd, (byte) 0x03, (byte) 0x01, (byte) 0x13, (byte) 0x8a, (byte) 0x6b, (byte) 0x3a, (byte) 0x91, (byte) 0x11, (byte) 0x41, (byte) 0x4f, (byte) 0x67, (byte) 0xdc, (byte) 0xea, (byte) 0x97, (byte) 0xf2, (byte) 0xcf, (byte) 0xce, (byte) 0xf0, (byte) 0xb4, (byte) 0xe6, (byte) 0x73, (byte) 0x96, (byte) 0xac, (byte) 0x74, (byte) 0x22, (byte) 0xe7, (byte) 0xad, (byte) 0x35, (byte) 0x85, (byte) 0xe2, (byte) 0xf9, (byte) 0x37, (byte) 0xe8, (byte) 0x1c, (byte) 0x75, (byte) 0xdf, (byte) 0x6e, (byte) 0x47, (byte) 0xf1, (byte) 0x1a, (byte) 0x71, (byte) 0x1d, (byte) 0x29, (byte) 0xc5, (byte) 0x89, (byte) 0x6f, (byte) 0xb7, (byte) 0x62, (byte) 0x0e, (byte) 0xaa, (byte) 0x18, (byte) 0xbe, (byte) 0x1b, (byte) 0xfc, (byte) 0x56, (byte) 0x3e, (byte) 0x4b, (byte) 0xc6, (byte) 0xd2, (byte) 0x79, (byte) 0x20, (byte) 0x9a, (byte) 0xdb, (byte) 0xc0, (byte) 0xfe, (byte) 0x78, (byte) 0xcd, (byte) 0x5a, (byte) 0xf4, (byte) 0x1f, (byte) 0xdd, (byte) 0xa8, (byte) 0x33, (byte) 0x88, (byte) 0x07, (byte) 0xc7, (byte) 0x31, (byte) 0xb1, (byte) 0x12, (byte) 0x10, (byte) 0x59, (byte) 0x27, (byte) 0x80, (byte) 0xec, (byte) 0x5f, (byte) 0x60, (byte) 0x51, (byte) 0x7f, (byte) 0xa9, (byte) 0x19, (byte) 0xb5, (byte) 0x4a, (byte) 0x0d, (byte) 0x2d, (byte) 0xe5, (byte) 0x7a, (byte) 0x9f, (byte) 0x93, (byte) 0xc9, (byte) 0x9c, (byte) 0xef, (byte) 0xa0, (byte) 0xe0, (byte) 0x3b, (byte) 0x4d, (byte) 0xae, (byte) 0x2a, (byte) 0xf5, (byte) 0xb0, (byte) 0xc8, (byte) 0xeb, (byte) 0xbb, (byte) 0x3c, (byte) 0x83, (byte) 0x53, (byte) 0x99, (byte) 0x61, (byte) 0x17, (byte) 0x2b, (byte) 0x04, (byte) 0x7e, (byte) 0xba, (byte) 0x77, (byte) 0xd6, (byte) 0x26, (byte) 0xe1, (byte) 0x69, (byte) 0x14, (byte) 0x63, (byte) 0x55, (byte) 0x21, (byte) 0x0c, (byte) 0x7d}; /** * Substitutes all {@code byte}s in a word. The word array will be changed. * * @param value array in which the first {@code WORD_SIZE} {@code byte}s will be substituted. * This array will be modified. * @return returns the modified {@code value} */ private byte[] substituteWord(byte[] value) { for (int i = 0; i < WORD_SIZE; ++i) { value[i] = this._sBox[value[i] & 0xff]; } return value; } /** * Rotate the {@code byte}'s in a word. The {@code byte}'s will be cycled left by one * {@code byte}. The modification will be in place, so the original argument is changed after * the method invocation. * * @param value Array in which the first {@code WORD_SIZE} {@code byte}'s will be changed due to * the rotation. The contents of this array is changed by this invocation. */ private byte[] rotate(byte[] value) { byte tmp = value[0]; for (int i = 1; i < WORD_SIZE; ++i) { value[i - 1] = value[i]; } value[WORD_SIZE - 1] = tmp; return value; } /** * Expands the key. The incoming key is {@code KEY_SIZE} {@code byte}s long. It will be expanded * to a length of {@code EXPANDED_KEY_SIZE} {@code byte}s. The expanded key will be stored in * {@link Aes256#_expandedKey}. *

* The encryption and decryption will use the expanded key. *

* * @param key key for the AES algorithm */ public Aes256(byte[] key) { this._expandedKey = new byte[EXPANDED_KEY_SIZE]; this._tmp = new byte[BLOCK_SIZE]; System.arraycopy(key, 0, this._expandedKey, 0, KEY_SIZE); for (int i = KEY_SIZE; i < EXPANDED_KEY_SIZE; i += WORD_SIZE) { System.arraycopy(this._expandedKey, i - WORD_SIZE, this._tmp, 0, WORD_SIZE); if (i % KEY_SIZE == 0) { substituteWord(rotate(this._tmp)); this._tmp[0] ^= 1 << (i / KEY_SIZE - 1); } else if (i % KEY_SIZE == BLOCK_SIZE) { substituteWord(this._tmp); } for (int j = 0; j < WORD_SIZE; ++j) { this._expandedKey[i + j] = (byte) (this._expandedKey[i - KEY_SIZE + j] ^ this._tmp[j]); } } } /** * Combines the state with the expanded key. The {@code byte}s will be combined by {@code XOR}. * * @param index start of the part of the expanded key, that will be used for the combination */ private void addRoundKey(int index) { for (int i = 0; i < BLOCK_SIZE; ++i) { this._tmp[i] = (byte) (this._tmp[i] ^ this._expandedKey[index + i]); } } /** * The polynomial represented by {@code b} will be multiplied by its free variable. This * multiplication takes place in a finite field. The resulting polynomial can still be represented * in one {@code byte}. *

* The bits {@code 0} to {@code 7} are the coefficients of the powers {@code x} to {@code x**8}. *

* * @param b origin polynomial * @return multiplied polynomial */ private int times2(int b) { int result = b << 1; if ((b & 0x80) != 0) { result ^= 0x1b; } return result & 0xff; } /** * Two polynomial will be multiplied with each other. The representation of the polynomial is * described in {@link Aes256#times2}. *

* The multiplication will be performed by successive invocations of {@link Aes256#times2}. *

* * @param a first polynomial * @param b second polynomial * @return result of the multiplication */ private byte mul(int a, byte b) { int result = 0; int first = a; int current = b & 0xff; while (first != 0) { if ((first & 0x01) != 0) { result ^= current; } first >>= 1; current = times2(current); } return (byte) (result & 0xff); } /** * Rotates the last three rows of the state. This method inverses {@link Aes256#shiftRows}. */ private void invShiftRows() { byte tmp = this._tmp[13]; this._tmp[13] = this._tmp[9]; this._tmp[9] = this._tmp[5]; this._tmp[5] = this._tmp[1]; this._tmp[1] = tmp; tmp = this._tmp[2]; this._tmp[2] = this._tmp[10]; this._tmp[10] = tmp; tmp = this._tmp[6]; this._tmp[6] = this._tmp[14]; this._tmp[14] = tmp; tmp = this._tmp[3]; this._tmp[3] = this._tmp[7]; this._tmp[7] = this._tmp[11]; this._tmp[11] = this._tmp[15]; this._tmp[15] = tmp; } /** * Changes all {@code byte}s of the state. This method is the inverse of * {@link Aes256#shiftRows}. */ private void invSubstituteState() { for (int i = 0; i < BLOCK_SIZE; ++i) { this._tmp[i] = this._invSBox[this._tmp[i] & 0xff]; } } /** * Mixes a column of the state. This method inverses {@link Aes256#mixColumn}. * * @param index position of the first entry of the row */ private void invMixColumn(int index) { int s0 = mul(0x0e, this._tmp[index]) ^ mul(0x0b, this._tmp[index + 1]) ^ mul(0x0d, this._tmp[index + 2]) ^ mul(0x09, this._tmp[index + 3]); int s1 = mul(0x09, this._tmp[index]) ^ mul(0x0e, this._tmp[index + 1]) ^ mul(0x0b, this._tmp[index + 2]) ^ mul(0x0d, this._tmp[index + 3]); int s2 = mul(0x0d, this._tmp[index]) ^ mul(0x09, this._tmp[index + 1]) ^ mul(0x0e, this._tmp[index + 2]) ^ mul(0x0b, this._tmp[index + 3]); int s3 = mul(0x0b, this._tmp[index]) ^ mul(0x0d, this._tmp[index + 1]) ^ mul(0x09, this._tmp[index + 2]) ^ mul(0x0e, this._tmp[index + 3]); this._tmp[index] = (byte) (s0 & 0xff); this._tmp[index + 1] = (byte) (s1 & 0xff); this._tmp[index + 2] = (byte) (s2 & 0xff); this._tmp[index + 3] = (byte) (s3 & 0xff); } /** * Mixes all columns of the state. This method inverses {@link Aes256#mixColumns}. */ private void invMixColumns() { invMixColumn(0); invMixColumn(4); invMixColumn(8); invMixColumn(12); } /** * Decrypts a block. The encrypted block starts at {@code inIndex} in {@code inBlock}. * {@code inBlock} won't be modified by this method. The decrypted block will be stored at * {@code outIndex} in {@code outBlock}. * * @param inBlock array containing the encrypted block * @param inIndex starting point of the encrypted block * @param outBlock array to store the decrypted block * @param outIndex position of the decrypted block */ public void decrypt(byte[] inBlock, int inIndex, byte[] outBlock, int outIndex) { System.arraycopy(inBlock, inIndex, this._tmp, 0, BLOCK_SIZE); addRoundKey(ROUNDS * BLOCK_SIZE); for (int round = ROUNDS - 1; round > 0; --round) { invShiftRows(); invSubstituteState(); addRoundKey(round * BLOCK_SIZE); invMixColumns(); } invShiftRows(); invSubstituteState(); addRoundKey(0); System.arraycopy(this._tmp, 0, outBlock, outIndex, BLOCK_SIZE); } } static class Cbc { /** * size of a block in {@code byte}s */ private static final int BLOCK_SIZE = 16; /** * cipher */ private final Aes256 _cipher; /** * last calculated block */ private final byte[] _current; /** * temporary block. It will only be used for decryption. */ private byte[] _buffer = null; /** * temporary block. */ private final byte[] _tmp; /** * buffer of the last output block. It will only be used for decryption. */ private byte[] _outBuffer = null; /** * Is the output buffer filled? */ private boolean _outBufferUsed = false; /** * temporary buffer to accumulate whole blocks of data */ private final byte[] _overflow; /** * How many {@code byte}s of {@link Cbc#_overflow} are used? */ private int _overflowUsed; private final OutputStream _output; /** * Creates the temporary buffers. * * @param iv initial value of {@link Cbc#_tmp} * @param key key for {@link Cbc#_cipher} * @param output stream where the encrypted or decrypted data is written */ public Cbc(byte[] iv, byte[] key, OutputStream output) { this._cipher = new Aes256(key); this._current = new byte[BLOCK_SIZE]; System.arraycopy(iv, 0, this._current, 0, BLOCK_SIZE); this._tmp = new byte[BLOCK_SIZE]; this._buffer = new byte[BLOCK_SIZE]; this._outBuffer = new byte[BLOCK_SIZE]; this._outBufferUsed = false; this._overflow = new byte[BLOCK_SIZE]; this._overflowUsed = 0; this._output = output; } /** * Decrypts a block. {@link Cbc#_current} will be modified. * * @param inBuffer storage of the encrypted block * @param outBuffer storage of the decrypted block */ private void decryptBlock(byte[] inBuffer) { System.arraycopy(inBuffer, 0, this._buffer, 0, BLOCK_SIZE); this._cipher.decrypt(this._buffer, 0, this._tmp, 0); for (int i = 0; i < BLOCK_SIZE; ++i) { this._tmp[i] ^= this._current[i]; this._current[i] = this._buffer[i]; this._outBuffer[i] = this._tmp[i]; } } /** * Decrypts the array. The whole array will be decrypted. * * @param data {@code byte}s that should be decrypted * @throws IOException if the writing fails */ public void decrypt(byte[] data) throws IOException { if (data != null) { decrypt(data, data.length); } } /** * Decrypts a part of the array. Only the first {@code length} {@code byte}s of the array will * be decrypted. * * @param data {@code byte}s that should be decrypted * @param length number of {@code byte}s that should be decrypted * @throws IOException if the writing fails */ public void decrypt(byte[] data, int length) throws IOException { if (data == null || length <= 0) { return; } for (int i = 0; i < length; ++i) { this._overflow[this._overflowUsed++] = data[i]; if (this._overflowUsed == BLOCK_SIZE) { if (this._outBufferUsed) { this._output.write(this._outBuffer); } decryptBlock(this._overflow); this._outBufferUsed = true; this._overflowUsed = 0; } } } /** * Finishes the decryption process. * * @throws DecryptException if the last block is no legal conclusion of the stream * @throws IOException if the writing fails */ public void finishDecryption() throws DecryptException, IOException { if (this._overflowUsed != 0) { // throw new DecryptException(); } if (!this._outBufferUsed) { return; } int pad = this._outBuffer[BLOCK_SIZE - 1] & 0xff; if (pad <= 0 || pad > BLOCK_SIZE) { // throw new DecryptException(); } // int left = BLOCK_SIZE - pad; // if (left > 0) { this._output.write(this._outBuffer, 0, 16); // } this._output.close(); } } private static final class DecryptException extends Exception { private static final long serialVersionUID = -935882404526228391L; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy