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

org.bouncycastle.crypto.engines.PhotonBeetleEngine Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.

The newest version!
package org.bouncycastle.crypto.engines;

import java.io.ByteArrayOutputStream;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
import org.bouncycastle.crypto.modes.AEADCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;

/**
 * Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/
 * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/photon-beetle-spec-final.pdf
 * 

* Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software *

*/ public class PhotonBeetleEngine implements AEADCipher { public enum PhotonBeetleParameters { pb32, pb128 } private boolean input_empty; private boolean forEncryption; private byte[] K; private byte[] N; private byte[] state; private byte[][] state_2d; private byte[] A; private byte[] T; private boolean encrypted; private boolean initialised; private final ByteArrayOutputStream aadData = new ByteArrayOutputStream(); private final ByteArrayOutputStream message = new ByteArrayOutputStream(); private final int CRYPTO_KEYBYTES = 16; private final int CRYPTO_NPUBBYTES = 16; private final int RATE_INBYTES; private final int RATE_INBYTES_HALF; private final int STATE_INBYTES; private final int TAG_INBYTES = 16; private final int LAST_THREE_BITS_OFFSET; private final int ROUND = 12; private final int D = 8; private final int Dq = 3; private final int Dr = 7; private final int DSquare = 64; private final int S = 4; private final int S_1 = 3; private final byte[][] RC = { {1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10}, {0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11}, {2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9}, {6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13}, {14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5}, {15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4}, {13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6}, {9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2} }; private final byte[][] MixColMatrix = { {2, 4, 2, 11, 2, 8, 5, 6}, {12, 9, 8, 13, 7, 7, 5, 2}, {4, 4, 13, 13, 9, 4, 13, 9}, {1, 6, 5, 1, 12, 13, 15, 14}, {15, 12, 9, 13, 14, 5, 14, 13}, {9, 14, 5, 15, 4, 12, 9, 6}, {12, 2, 2, 10, 3, 1, 1, 14}, {15, 1, 13, 10, 5, 10, 2, 3} }; private final byte[] sbox = {12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2}; public PhotonBeetleEngine(PhotonBeetleParameters pbp) { int CAPACITY_INBITS = 0, RATE_INBITS = 0; switch (pbp) { case pb32: RATE_INBITS = 32; CAPACITY_INBITS = 224; break; case pb128: RATE_INBITS = 128; CAPACITY_INBITS = 128; break; } RATE_INBYTES = (RATE_INBITS + 7) >>> 3; RATE_INBYTES_HALF = RATE_INBYTES >>> 1; int STATE_INBITS = RATE_INBITS + CAPACITY_INBITS; STATE_INBYTES = (STATE_INBITS + 7) >>> 3; LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3); initialised = false; } @Override public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException { this.forEncryption = forEncryption; if (!(params instanceof ParametersWithIV)) { throw new IllegalArgumentException("Photon-Beetle AEAD init parameters must include an IV"); } ParametersWithIV ivParams = (ParametersWithIV)params; N = ivParams.getIV(); if (N == null || N.length != CRYPTO_NPUBBYTES) { throw new IllegalArgumentException("Photon-Beetle AEAD requires exactly 16 bytes of IV"); } if (!(ivParams.getParameters() instanceof KeyParameter)) { throw new IllegalArgumentException("Photon-Beetle AEAD init parameters must include a key"); } KeyParameter key = (KeyParameter)ivParams.getParameters(); K = key.getKey(); if (K.length != CRYPTO_KEYBYTES) { throw new IllegalArgumentException("Photon-Beetle AEAD key must be 128 bits long"); } CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties( this.getAlgorithmName(), 128, params, Utils.getPurpose(forEncryption))); state = new byte[STATE_INBYTES]; state_2d = new byte[D][D]; T = new byte[TAG_INBYTES]; initialised = true; reset(false); } @Override public String getAlgorithmName() { return "Photon-Beetle AEAD"; } @Override public void processAADByte(byte input) { aadData.write(input); } @Override public void processAADBytes(byte[] input, int inOff, int len) { if (inOff + len > input.length) { throw new DataLengthException("input buffer too short"); } aadData.write(input, inOff, len); } @Override public int processByte(byte input, byte[] output, int outOff) throws DataLengthException { return processBytes(new byte[]{input}, 0, 1, output, outOff); } @Override public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) throws DataLengthException { if (inOff + len > input.length) { throw new DataLengthException("input buffer too short"); } message.write(input, inOff, len); return 0; } @Override public int doFinal(byte[] output, int outOff) throws IllegalStateException, InvalidCipherTextException { if (!initialised) { throw new IllegalArgumentException("Need call init function before encryption/decryption"); } int len = message.size() - (forEncryption ? 0 : TAG_INBYTES); if ((forEncryption && len + TAG_INBYTES + outOff > output.length) || (!forEncryption && len + outOff > output.length)) { throw new OutputLengthException("output buffer too short"); } byte[] input = message.toByteArray(); int inOff = 0; A = aadData.toByteArray(); int adlen = A.length, i; if (adlen != 0 || len != 0) { input_empty = false; } byte c0 = select((len != 0), ((adlen % RATE_INBYTES) == 0), (byte)3, (byte)4); byte c1 = select((adlen != 0), ((len % RATE_INBYTES) == 0), (byte)5, (byte)6); int Dlen_inblocks, LastDBlocklen; if (adlen != 0) { Dlen_inblocks = (adlen + RATE_INBYTES - 1) / RATE_INBYTES; for (i = 0; i < Dlen_inblocks - 1; i++) { PHOTON_Permutation(); XOR(A, i * RATE_INBYTES, RATE_INBYTES); } PHOTON_Permutation(); LastDBlocklen = adlen - i * RATE_INBYTES; XOR(A, i * RATE_INBYTES, LastDBlocklen); if (LastDBlocklen < RATE_INBYTES) { state[LastDBlocklen] ^= 0x01; // ozs } state[STATE_INBYTES - 1] ^= c0 << LAST_THREE_BITS_OFFSET; } if (len != 0) { Dlen_inblocks = (len + RATE_INBYTES - 1) / RATE_INBYTES; for (i = 0; i < Dlen_inblocks - 1; i++) { PHOTON_Permutation(); rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, RATE_INBYTES); } PHOTON_Permutation(); LastDBlocklen = len - i * RATE_INBYTES; rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, LastDBlocklen); if (LastDBlocklen < RATE_INBYTES) { state[LastDBlocklen] ^= 0x01; // ozs } state[STATE_INBYTES - 1] ^= c1 << LAST_THREE_BITS_OFFSET; } outOff += len; if (input_empty) { state[STATE_INBYTES - 1] ^= 1 << LAST_THREE_BITS_OFFSET; } PHOTON_Permutation(); T = new byte[TAG_INBYTES]; System.arraycopy(state, 0, T, 0, TAG_INBYTES); if (forEncryption) { System.arraycopy(T, 0, output, outOff, TAG_INBYTES); len += TAG_INBYTES; } else { for (i = 0; i < TAG_INBYTES; ++i) { if (T[i] != input[len + i]) { throw new IllegalArgumentException("Mac does not match"); } } } reset(false); return len; } @Override public byte[] getMac() { return T; } @Override public int getUpdateOutputSize(int len) { return len; } @Override public int getOutputSize(int len) { return len + TAG_INBYTES; } @Override public void reset() { if (!initialised) { throw new IllegalArgumentException("Need call init function before encryption/decryption"); } reset(true); } private void reset(boolean clearMac) { if (clearMac) { T = null; } input_empty = true; aadData.reset(); message.reset(); System.arraycopy(K, 0, state, 0, K.length); System.arraycopy(N, 0, state, K.length, N.length); encrypted = false; } private void PHOTON_Permutation() { int i, j, k, l; for (i = 0; i < DSquare; i++) { state_2d[i >>> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >>> (4 * (i & 1))) & 0xf); } for (int round = 0; round < ROUND; round++) { //AddKey for (i = 0; i < D; i++) { state_2d[i][0] ^= RC[i][round]; } //SubCell for (i = 0; i < D; i++) { for (j = 0; j < D; j++) { state_2d[i][j] = sbox[state_2d[i][j]]; } } //ShiftRow for (i = 1; i < D; i++) { System.arraycopy(state_2d[i], 0, state, 0, D); System.arraycopy(state, i, state_2d[i], 0, D - i); System.arraycopy(state, 0, state_2d[i], D - i, i); } //MixColumn for (j = 0; j < D; j++) { for (i = 0; i < D; i++) { byte sum = 0; for (k = 0; k < D; k++) { int x = MixColMatrix[i][k], ret = 0, b = state_2d[k][j]; for (l = 0; l < S; l++) { if (((b >>> l) & 1) != 0) { ret ^= x; } if (((x >>> S_1) & 1) != 0) { x <<= 1; x ^= 0x3; } else { x <<= 1; } } sum ^= ret & 15; } state[i] = sum; } for (i = 0; i < D; i++) { state_2d[i][j] = state[i]; } } } for (i = 0; i < DSquare; i += 2) { state[i >>> 1] = (byte)(((state_2d[i >>> Dq][i & Dr] & 0xf)) | ((state_2d[i >>> Dq][(i + 1) & Dr] & 0xf) << 4)); } } private byte select(boolean condition1, boolean condition2, byte option3, byte option4) { if (condition1 && condition2) { return 1; } if (condition1) { return 2; } if (condition2) { return option3; } return option4; } private void rhoohr(byte[] ciphertext, int outOff, byte[] plaintext, int inOff, int DBlen_inbytes) { byte[] OuterState_part1_ROTR1 = state_2d[0]; int i, loop_end = Math.min(DBlen_inbytes, RATE_INBYTES_HALF); for (i = 0; i < RATE_INBYTES_HALF - 1; i++) { OuterState_part1_ROTR1[i] = (byte)(((state[i] & 0xFF) >>> 1) | ((state[(i + 1)] & 1) << 7)); } OuterState_part1_ROTR1[RATE_INBYTES_HALF - 1] = (byte)(((state[i] & 0xFF) >>> 1) | ((state[0] & 1) << 7)); i = 0; while (i < loop_end) { ciphertext[i + outOff] = (byte)(state[i + RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]); } while (i < DBlen_inbytes) { ciphertext[i + outOff] = (byte)(OuterState_part1_ROTR1[i - RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]); } if (forEncryption) { XOR(plaintext, inOff, DBlen_inbytes); } else { XOR(ciphertext, inOff, DBlen_inbytes); } } private void XOR(byte[] in_right, int rOff, int iolen_inbytes) { for (int i = 0; i < iolen_inbytes; i++) { state[i] ^= in_right[rOff++]; } } public int getBlockSize() { return RATE_INBYTES; } public int getKeyBytesSize() { return CRYPTO_KEYBYTES; } public int getIVBytesSize() { return CRYPTO_NPUBBYTES; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy