001: package org.bouncycastle.crypto.encodings;
002:
003: import org.bouncycastle.crypto.AsymmetricBlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.InvalidCipherTextException;
006: import org.bouncycastle.crypto.params.ParametersWithRandom;
007: import org.bouncycastle.crypto.params.RSAKeyParameters;
008:
009: /**
010: * ISO 9796-1 padding. Note in the light of recent results you should
011: * only use this with RSA (rather than the "simpler" Rabin keys) and you
012: * should never use it with anything other than a hash (ie. even if the
013: * message is small don't sign the message, sign it's hash) or some "random"
014: * value. See your favorite search engine for details.
015: */
016: public class ISO9796d1Encoding implements AsymmetricBlockCipher {
017: private static byte[] shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4,
018: 0x2, 0xf, 0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
019: private static byte[] inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2,
020: 0xb, 0xc, 0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 };
021:
022: private AsymmetricBlockCipher engine;
023: private boolean forEncryption;
024: private int bitSize;
025: private int padBits = 0;
026:
027: public ISO9796d1Encoding(AsymmetricBlockCipher cipher) {
028: this .engine = cipher;
029: }
030:
031: public AsymmetricBlockCipher getUnderlyingCipher() {
032: return engine;
033: }
034:
035: public void init(boolean forEncryption, CipherParameters param) {
036: RSAKeyParameters kParam = null;
037:
038: if (param instanceof ParametersWithRandom) {
039: ParametersWithRandom rParam = (ParametersWithRandom) param;
040:
041: kParam = (RSAKeyParameters) rParam.getParameters();
042: } else {
043: kParam = (RSAKeyParameters) param;
044: }
045:
046: engine.init(forEncryption, param);
047:
048: bitSize = kParam.getModulus().bitLength();
049:
050: this .forEncryption = forEncryption;
051: }
052:
053: /**
054: * return the input block size. The largest message we can process
055: * is (key_size_in_bits + 3)/16, which in our world comes to
056: * key_size_in_bytes / 2.
057: */
058: public int getInputBlockSize() {
059: int baseBlockSize = engine.getInputBlockSize();
060:
061: if (forEncryption) {
062: return (baseBlockSize + 1) / 2;
063: } else {
064: return baseBlockSize;
065: }
066: }
067:
068: /**
069: * return the maximum possible size for the output.
070: */
071: public int getOutputBlockSize() {
072: int baseBlockSize = engine.getOutputBlockSize();
073:
074: if (forEncryption) {
075: return baseBlockSize;
076: } else {
077: return (baseBlockSize + 1) / 2;
078: }
079: }
080:
081: /**
082: * set the number of bits in the next message to be treated as
083: * pad bits.
084: */
085: public void setPadBits(int padBits) {
086: if (padBits > 7) {
087: throw new IllegalArgumentException("padBits > 7");
088: }
089:
090: this .padBits = padBits;
091: }
092:
093: /**
094: * retrieve the number of pad bits in the last decoded message.
095: */
096: public int getPadBits() {
097: return padBits;
098: }
099:
100: public byte[] processBlock(byte[] in, int inOff, int inLen)
101: throws InvalidCipherTextException {
102: if (forEncryption) {
103: return encodeBlock(in, inOff, inLen);
104: } else {
105: return decodeBlock(in, inOff, inLen);
106: }
107: }
108:
109: private byte[] encodeBlock(byte[] in, int inOff, int inLen)
110: throws InvalidCipherTextException {
111: byte[] block = new byte[(bitSize + 7) / 8];
112: int r = padBits + 1;
113: int z = inLen;
114: int t = (bitSize + 13) / 16;
115:
116: for (int i = 0; i < t; i += z) {
117: if (i > t - z) {
118: System.arraycopy(in, inOff + inLen - (t - i), block,
119: block.length - t, t - i);
120: } else {
121: System.arraycopy(in, inOff, block, block.length
122: - (i + z), z);
123: }
124: }
125:
126: for (int i = block.length - 2 * t; i != block.length; i += 2) {
127: byte val = block[block.length - t + i / 2];
128:
129: block[i] = (byte) ((shadows[(val & 0xff) >>> 4] << 4) | shadows[val & 0x0f]);
130: block[i + 1] = val;
131: }
132:
133: block[block.length - 2 * z] ^= r;
134: block[block.length - 1] = (byte) ((block[block.length - 1] << 4) | 0x06);
135:
136: int maxBit = (8 - (bitSize - 1) % 8);
137: int offSet = 0;
138:
139: if (maxBit != 8) {
140: block[0] &= 0xff >>> maxBit;
141: block[0] |= 0x80 >>> maxBit;
142: } else {
143: block[0] = 0x00;
144: block[1] |= 0x80;
145: offSet = 1;
146: }
147:
148: return engine
149: .processBlock(block, offSet, block.length - offSet);
150: }
151:
152: /**
153: * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
154: */
155: private byte[] decodeBlock(byte[] in, int inOff, int inLen)
156: throws InvalidCipherTextException {
157: byte[] block = engine.processBlock(in, inOff, inLen);
158: int r = 1;
159: int t = (bitSize + 13) / 16;
160:
161: if ((block[block.length - 1] & 0x0f) != 0x6) {
162: throw new InvalidCipherTextException(
163: "invalid forcing byte in block");
164: }
165:
166: block[block.length - 1] = (byte) (((block[block.length - 1] & 0xff) >>> 4) | ((inverse[(block[block.length - 2] & 0xff) >> 4]) << 4));
167: block[0] = (byte) ((shadows[(block[1] & 0xff) >>> 4] << 4) | shadows[block[1] & 0x0f]);
168:
169: boolean boundaryFound = false;
170: int boundary = 0;
171:
172: for (int i = block.length - 1; i >= block.length - 2 * t; i -= 2) {
173: int val = ((shadows[(block[i] & 0xff) >>> 4] << 4) | shadows[block[i] & 0x0f]);
174:
175: if (((block[i - 1] ^ val) & 0xff) != 0) {
176: if (!boundaryFound) {
177: boundaryFound = true;
178: r = (block[i - 1] ^ val) & 0xff;
179: boundary = i - 1;
180: } else {
181: throw new InvalidCipherTextException(
182: "invalid tsums in block");
183: }
184: }
185: }
186:
187: block[boundary] = 0;
188:
189: byte[] nblock = new byte[(block.length - boundary) / 2];
190:
191: for (int i = 0; i < nblock.length; i++) {
192: nblock[i] = block[2 * i + boundary + 1];
193: }
194:
195: padBits = r - 1;
196:
197: return nblock;
198: }
199: }
|