001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.DataLengthException;
006: import org.bouncycastle.crypto.InvalidCipherTextException;
007: import org.bouncycastle.crypto.Wrapper;
008: import org.bouncycastle.crypto.params.KeyParameter;
009: import org.bouncycastle.crypto.params.ParametersWithIV;
010:
011: /**
012: * an implementation of the AES Key Wrapper from the NIST Key Wrap
013: * Specification as described in RFC 3394.
014: * <p>
015: * For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
016: * and <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
017: */
018: public class RFC3394WrapEngine implements Wrapper {
019: private BlockCipher engine;
020: private KeyParameter param;
021: private boolean forWrapping;
022:
023: private byte[] iv = { (byte) 0xa6, (byte) 0xa6, (byte) 0xa6,
024: (byte) 0xa6, (byte) 0xa6, (byte) 0xa6, (byte) 0xa6,
025: (byte) 0xa6 };
026:
027: public RFC3394WrapEngine(BlockCipher engine) {
028: this .engine = engine;
029: }
030:
031: public void init(boolean forWrapping, CipherParameters param) {
032: this .forWrapping = forWrapping;
033:
034: if (param instanceof KeyParameter) {
035: this .param = (KeyParameter) param;
036: } else if (param instanceof ParametersWithIV) {
037: this .iv = ((ParametersWithIV) param).getIV();
038: this .param = (KeyParameter) ((ParametersWithIV) param)
039: .getParameters();
040: if (this .iv.length != 8) {
041: throw new IllegalArgumentException("IV not equal to 8");
042: }
043: }
044: }
045:
046: public String getAlgorithmName() {
047: return engine.getAlgorithmName();
048: }
049:
050: public byte[] wrap(byte[] in, int inOff, int inLen) {
051: if (!forWrapping) {
052: throw new IllegalStateException("not set for wrapping");
053: }
054:
055: int n = inLen / 8;
056:
057: if ((n * 8) != inLen) {
058: throw new DataLengthException(
059: "wrap data must be a multiple of 8 bytes");
060: }
061:
062: byte[] block = new byte[inLen + iv.length];
063: byte[] buf = new byte[8 + iv.length];
064:
065: System.arraycopy(iv, 0, block, 0, iv.length);
066: System.arraycopy(in, 0, block, iv.length, inLen);
067:
068: engine.init(true, param);
069:
070: for (int j = 0; j != 6; j++) {
071: for (int i = 1; i <= n; i++) {
072: System.arraycopy(block, 0, buf, 0, iv.length);
073: System.arraycopy(block, 8 * i, buf, iv.length, 8);
074: engine.processBlock(buf, 0, buf, 0);
075:
076: int t = n * j + i;
077: for (int k = 1; t != 0; k++) {
078: byte v = (byte) t;
079:
080: buf[iv.length - k] ^= v;
081:
082: t >>>= 8;
083: }
084:
085: System.arraycopy(buf, 0, block, 0, 8);
086: System.arraycopy(buf, 8, block, 8 * i, 8);
087: }
088: }
089:
090: return block;
091: }
092:
093: public byte[] unwrap(byte[] in, int inOff, int inLen)
094: throws InvalidCipherTextException {
095: if (forWrapping) {
096: throw new IllegalStateException("not set for unwrapping");
097: }
098:
099: int n = inLen / 8;
100:
101: if ((n * 8) != inLen) {
102: throw new InvalidCipherTextException(
103: "unwrap data must be a multiple of 8 bytes");
104: }
105:
106: byte[] block = new byte[inLen - iv.length];
107: byte[] a = new byte[iv.length];
108: byte[] buf = new byte[8 + iv.length];
109:
110: System.arraycopy(in, 0, a, 0, iv.length);
111: System.arraycopy(in, iv.length, block, 0, inLen - iv.length);
112:
113: engine.init(false, param);
114:
115: n = n - 1;
116:
117: for (int j = 5; j >= 0; j--) {
118: for (int i = n; i >= 1; i--) {
119: System.arraycopy(a, 0, buf, 0, iv.length);
120: System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8);
121:
122: int t = n * j + i;
123: for (int k = 1; t != 0; k++) {
124: byte v = (byte) t;
125:
126: buf[iv.length - k] ^= v;
127:
128: t >>>= 8;
129: }
130:
131: engine.processBlock(buf, 0, buf, 0);
132: System.arraycopy(buf, 0, a, 0, 8);
133: System.arraycopy(buf, 8, block, 8 * (i - 1), 8);
134: }
135: }
136:
137: for (int i = 0; i != iv.length; i++) {
138: if (a[i] != iv[i]) {
139: throw new InvalidCipherTextException("checksum failed");
140: }
141: }
142:
143: return block;
144: }
145: }
|