001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.InvalidCipherTextException;
006: import org.bouncycastle.crypto.Wrapper;
007: import org.bouncycastle.crypto.modes.CBCBlockCipher;
008: import org.bouncycastle.crypto.params.ParametersWithIV;
009: import org.bouncycastle.crypto.params.ParametersWithRandom;
010:
011: import java.security.SecureRandom;
012:
013: /**
014: * an implementation of the RFC 3211 Key Wrap
015: * Specification.
016: */
017: public class RFC3211WrapEngine implements Wrapper {
018: private CBCBlockCipher engine;
019: private ParametersWithIV param;
020: private boolean forWrapping;
021: private SecureRandom rand;
022:
023: public RFC3211WrapEngine(BlockCipher engine) {
024: this .engine = new CBCBlockCipher(engine);
025: }
026:
027: public void init(boolean forWrapping, CipherParameters param) {
028: this .forWrapping = forWrapping;
029:
030: if (param instanceof ParametersWithRandom) {
031: ParametersWithRandom p = (ParametersWithRandom) param;
032:
033: rand = p.getRandom();
034: this .param = (ParametersWithIV) p.getParameters();
035: } else {
036: if (forWrapping) {
037: rand = new SecureRandom();
038: }
039:
040: this .param = (ParametersWithIV) param;
041: }
042: }
043:
044: public String getAlgorithmName() {
045: return engine.getUnderlyingCipher().getAlgorithmName()
046: + "/RFC3211Wrap";
047: }
048:
049: public byte[] wrap(byte[] in, int inOff, int inLen) {
050: if (!forWrapping) {
051: throw new IllegalStateException("not set for wrapping");
052: }
053:
054: engine.init(true, param);
055:
056: int blockSize = engine.getBlockSize();
057: byte[] cekBlock;
058:
059: if (inLen + 4 < blockSize * 2) {
060: cekBlock = new byte[blockSize * 2];
061: } else {
062: cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4
063: : ((inLen + 4) / blockSize + 1) * blockSize];
064: }
065:
066: cekBlock[0] = (byte) inLen;
067: cekBlock[1] = (byte) ~in[inOff];
068: cekBlock[2] = (byte) ~in[inOff + 1];
069: cekBlock[3] = (byte) ~in[inOff + 2];
070:
071: System.arraycopy(in, inOff, cekBlock, 4, inLen);
072:
073: for (int i = inLen + 4; i < cekBlock.length; i++) {
074: cekBlock[i] = (byte) rand.nextInt();
075: }
076:
077: for (int i = 0; i < cekBlock.length; i += blockSize) {
078: engine.processBlock(cekBlock, i, cekBlock, i);
079: }
080:
081: for (int i = 0; i < cekBlock.length; i += blockSize) {
082: engine.processBlock(cekBlock, i, cekBlock, i);
083: }
084:
085: return cekBlock;
086: }
087:
088: public byte[] unwrap(byte[] in, int inOff, int inLen)
089: throws InvalidCipherTextException {
090: if (forWrapping) {
091: throw new IllegalStateException("not set for unwrapping");
092: }
093:
094: int blockSize = engine.getBlockSize();
095:
096: if (inLen < 2 * blockSize) {
097: throw new InvalidCipherTextException("input too short");
098: }
099:
100: byte[] cekBlock = new byte[inLen];
101: byte[] iv = new byte[blockSize];
102:
103: System.arraycopy(in, inOff, cekBlock, 0, inLen);
104: System.arraycopy(in, inOff, iv, 0, iv.length);
105:
106: engine.init(false, new ParametersWithIV(param.getParameters(),
107: iv));
108:
109: for (int i = blockSize; i < cekBlock.length; i += blockSize) {
110: engine.processBlock(cekBlock, i, cekBlock, i);
111: }
112:
113: System.arraycopy(cekBlock, cekBlock.length - iv.length, iv, 0,
114: iv.length);
115:
116: engine.init(false, new ParametersWithIV(param.getParameters(),
117: iv));
118:
119: engine.processBlock(cekBlock, 0, cekBlock, 0);
120:
121: engine.init(false, param);
122:
123: for (int i = 0; i < cekBlock.length; i += blockSize) {
124: engine.processBlock(cekBlock, i, cekBlock, i);
125: }
126:
127: if ((cekBlock[0] & 0xff) > cekBlock.length - 4) {
128: throw new InvalidCipherTextException(
129: "wrapped key corrupted");
130: }
131:
132: byte[] key = new byte[cekBlock[0] & 0xff];
133:
134: System.arraycopy(cekBlock, 4, key, 0, cekBlock[0]);
135:
136: for (int i = 0; i != 3; i++) {
137: byte check = (byte) ~cekBlock[1 + i];
138: if (check != key[i]) {
139: throw new InvalidCipherTextException(
140: "wrapped key fails checksum");
141: }
142: }
143:
144: return key;
145: }
146: }
|