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

org.bouncycastle.crypto.engines.RFC3394WrapEngine 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 org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.util.Arrays;

/**
 * an implementation of the AES Key Wrapper from the NIST Key Wrap
 * Specification as described in RFC 3394.
 * 

* For further details see: https://www.ietf.org/rfc/rfc3394.txt * and https://csrc.nist.gov/encryption/kms/key-wrap.pdf. */ public class RFC3394WrapEngine implements Wrapper { private static final byte[] DEFAULT_IV = { (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 }; private final BlockCipher engine; private final boolean wrapCipherMode; private final byte[] iv = new byte[8]; private KeyParameter param = null; private boolean forWrapping = true; /** * Create a RFC 3394 WrapEngine specifying the encrypt for wrapping, decrypt for unwrapping. * * @param engine the block cipher to be used for wrapping. */ public RFC3394WrapEngine(BlockCipher engine) { this(engine, false); } /** * Create a RFC 3394 WrapEngine specifying the direction for wrapping and unwrapping.. * * @param engine the block cipher to be used for wrapping. * @param useReverseDirection true if engine should be used in decryption mode for wrapping, false otherwise. */ public RFC3394WrapEngine(BlockCipher engine, boolean useReverseDirection) { this.engine = engine; this.wrapCipherMode = !useReverseDirection; } public void init( boolean forWrapping, CipherParameters param) { this.forWrapping = forWrapping; if (param instanceof ParametersWithRandom) { param = ((ParametersWithRandom) param).getParameters(); } if (param instanceof KeyParameter) { this.param = (KeyParameter)param; System.arraycopy(DEFAULT_IV, 0, iv, 0, 8); } else if (param instanceof ParametersWithIV) { ParametersWithIV withIV = (ParametersWithIV)param; byte[] iv = withIV.getIV(); if (iv.length != 8) { throw new IllegalArgumentException("IV not equal to 8"); } this.param = (KeyParameter)withIV.getParameters(); System.arraycopy(iv, 0, this.iv, 0, 8); } else { // TODO Throw an exception for bad parameters? } } public String getAlgorithmName() { return engine.getAlgorithmName(); } public byte[] wrap( byte[] in, int inOff, int inLen) { if (!forWrapping) { throw new IllegalStateException("not set for wrapping"); } if (inLen < 8) { throw new DataLengthException("wrap data must be at least 8 bytes"); } int n = inLen / 8; if ((n * 8) != inLen) { throw new DataLengthException("wrap data must be a multiple of 8 bytes"); } engine.init(wrapCipherMode, param); byte[] block = new byte[inLen + iv.length]; System.arraycopy(iv, 0, block, 0, iv.length); System.arraycopy(in, inOff, block, iv.length, inLen); if (n == 1) { engine.processBlock(block, 0, block, 0); } else { byte[] buf = new byte[8 + iv.length]; for (int j = 0; j != 6; j++) { for (int i = 1; i <= n; i++) { System.arraycopy(block, 0, buf, 0, iv.length); System.arraycopy(block, 8 * i, buf, iv.length, 8); engine.processBlock(buf, 0, buf, 0); int t = n * j + i; for (int k = 1; t != 0; k++) { byte v = (byte)t; buf[iv.length - k] ^= v; t >>>= 8; } System.arraycopy(buf, 0, block, 0, 8); System.arraycopy(buf, 8, block, 8 * i, 8); } } } return block; } public byte[] unwrap( byte[] in, int inOff, int inLen) throws InvalidCipherTextException { if (forWrapping) { throw new IllegalStateException("not set for unwrapping"); } if (inLen < 16) { throw new InvalidCipherTextException("unwrap data too short"); } int n = inLen / 8; if ((n * 8) != inLen) { throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes"); } engine.init(!wrapCipherMode, param); byte[] block = new byte[inLen - iv.length]; byte[] a = new byte[iv.length]; byte[] buf = new byte[8 + iv.length]; n = n - 1; if (n == 1) { engine.processBlock(in, inOff, buf, 0); System.arraycopy(buf, 0, a, 0, iv.length); System.arraycopy(buf, iv.length, block, 0, 8); } else { System.arraycopy(in, inOff, a, 0, iv.length); System.arraycopy(in, inOff + iv.length, block, 0, inLen - iv.length); for (int j = 5; j >= 0; j--) { for (int i = n; i >= 1; i--) { System.arraycopy(a, 0, buf, 0, iv.length); System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8); int t = n * j + i; for (int k = 1; t != 0; k++) { byte v = (byte)t; buf[iv.length - k] ^= v; t >>>= 8; } engine.processBlock(buf, 0, buf, 0); System.arraycopy(buf, 0, a, 0, 8); System.arraycopy(buf, 8, block, 8 * (i - 1), 8); } } } if (n != 1) { if (!Arrays.constantTimeAreEqual(a, iv)) { throw new InvalidCipherTextException("checksum failed"); } } else { // TODO: old (incorrect) backwards compatible unwrap - will be removed. if (!Arrays.constantTimeAreEqual(a, iv)) { System.arraycopy(in, inOff, a, 0, iv.length); System.arraycopy(in, inOff + iv.length, block, 0, inLen - iv.length); for (int j = 5; j >= 0; j--) { System.arraycopy(a, 0, buf, 0, iv.length); System.arraycopy(block, 0, buf, iv.length, 8); int t = n * j + 1; for (int k = 1; t != 0; k++) { byte v = (byte)t; buf[iv.length - k] ^= v; t >>>= 8; } engine.processBlock(buf, 0, buf, 0); System.arraycopy(buf, 0, a, 0, 8); System.arraycopy(buf, 8, block, 0, 8); } if (!Arrays.constantTimeAreEqual(a, iv)) { throw new InvalidCipherTextException("checksum failed"); } } } return block; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy