001: package org.bouncycastle.crypto.signers;
002:
003: import org.bouncycastle.crypto.AsymmetricBlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.CryptoException;
006: import org.bouncycastle.crypto.DataLengthException;
007: import org.bouncycastle.crypto.Digest;
008: import org.bouncycastle.crypto.Signer;
009: import org.bouncycastle.crypto.params.ParametersWithRandom;
010: import org.bouncycastle.crypto.params.RSABlindingParameters;
011: import org.bouncycastle.crypto.params.RSAKeyParameters;
012:
013: import java.security.SecureRandom;
014:
015: /**
016: * RSA-PSS as described in PKCS# 1 v 2.1.
017: * <p>
018: * Note: the usual value for the salt length is the number of
019: * bytes in the hash function.
020: */
021: public class PSSSigner implements Signer {
022: static final public byte TRAILER_IMPLICIT = (byte) 0xBC;
023:
024: private Digest digest;
025: private AsymmetricBlockCipher cipher;
026: private SecureRandom random;
027:
028: private int hLen;
029: private int sLen;
030: private int emBits;
031: private byte[] salt;
032: private byte[] mDash;
033: private byte[] block;
034: private byte trailer;
035:
036: /**
037: * basic constructor
038: *
039: * @param cipher the assymetric cipher to use.
040: * @param digest the digest to use.
041: * @param sLen the length of the salt to use (in bytes).
042: */
043: public PSSSigner(AsymmetricBlockCipher cipher, Digest digest,
044: int sLen) {
045: this (cipher, digest, sLen, TRAILER_IMPLICIT);
046: }
047:
048: public PSSSigner(AsymmetricBlockCipher cipher, Digest digest,
049: int sLen, byte trailer) {
050: this .cipher = cipher;
051: this .digest = digest;
052: this .hLen = digest.getDigestSize();
053: this .sLen = sLen;
054: this .salt = new byte[sLen];
055: this .mDash = new byte[8 + sLen + hLen];
056: this .trailer = trailer;
057: }
058:
059: public void init(boolean forSigning, CipherParameters param) {
060: CipherParameters params;
061:
062: if (param instanceof ParametersWithRandom) {
063: ParametersWithRandom p = (ParametersWithRandom) param;
064:
065: params = p.getParameters();
066: random = p.getRandom();
067: } else {
068: params = param;
069: if (forSigning) {
070: random = new SecureRandom();
071: }
072: }
073:
074: cipher.init(forSigning, params);
075:
076: RSAKeyParameters kParam;
077:
078: if (params instanceof RSABlindingParameters) {
079: kParam = ((RSABlindingParameters) params).getPublicKey();
080: } else {
081: kParam = (RSAKeyParameters) params;
082: }
083:
084: emBits = kParam.getModulus().bitLength() - 1;
085:
086: block = new byte[(emBits + 7) / 8];
087:
088: reset();
089: }
090:
091: /**
092: * clear possible sensitive data
093: */
094: private void clearBlock(byte[] block) {
095: for (int i = 0; i != block.length; i++) {
096: block[i] = 0;
097: }
098: }
099:
100: /**
101: * update the internal digest with the byte b
102: */
103: public void update(byte b) {
104: digest.update(b);
105: }
106:
107: /**
108: * update the internal digest with the byte array in
109: */
110: public void update(byte[] in, int off, int len) {
111: digest.update(in, off, len);
112: }
113:
114: /**
115: * reset the internal state
116: */
117: public void reset() {
118: digest.reset();
119: }
120:
121: /**
122: * generate a signature for the message we've been loaded with using
123: * the key we were initialised with.
124: */
125: public byte[] generateSignature() throws CryptoException,
126: DataLengthException {
127: if (emBits < (8 * hLen + 8 * sLen + 9)) {
128: throw new DataLengthException("encoding error");
129: }
130:
131: digest.doFinal(mDash, mDash.length - hLen - sLen);
132:
133: if (sLen != 0) {
134: random.nextBytes(salt);
135:
136: System.arraycopy(salt, 0, mDash, mDash.length - sLen, sLen);
137: }
138:
139: byte[] h = new byte[hLen];
140:
141: digest.update(mDash, 0, mDash.length);
142:
143: digest.doFinal(h, 0);
144:
145: block[block.length - sLen - 1 - hLen - 1] = 0x01;
146: System.arraycopy(salt, 0, block,
147: block.length - sLen - hLen - 1, sLen);
148:
149: byte[] dbMask = maskGeneratorFunction1(h, 0, h.length,
150: block.length - hLen - 1);
151: for (int i = 0; i != dbMask.length; i++) {
152: block[i] ^= dbMask[i];
153: }
154:
155: block[0] &= (0xff >> ((block.length * 8) - emBits));
156:
157: System.arraycopy(h, 0, block, block.length - hLen - 1, hLen);
158:
159: block[block.length - 1] = trailer;
160:
161: byte[] b = cipher.processBlock(block, 0, block.length);
162:
163: clearBlock(block);
164:
165: return b;
166: }
167:
168: /**
169: * return true if the internal state represents the signature described
170: * in the passed in array.
171: */
172: public boolean verifySignature(byte[] signature) {
173: if (emBits < (8 * hLen + 8 * sLen + 9)) {
174: return false;
175: }
176:
177: digest.doFinal(mDash, mDash.length - hLen - sLen);
178:
179: try {
180: byte[] b = cipher.processBlock(signature, 0,
181: signature.length);
182: System.arraycopy(b, 0, block, block.length - b.length,
183: b.length);
184: } catch (Exception e) {
185: return false;
186: }
187:
188: if (block[block.length - 1] != trailer) {
189: clearBlock(block);
190: return false;
191: }
192:
193: byte[] dbMask = maskGeneratorFunction1(block, block.length
194: - hLen - 1, hLen, block.length - hLen - 1);
195:
196: for (int i = 0; i != dbMask.length; i++) {
197: block[i] ^= dbMask[i];
198: }
199:
200: block[0] &= (0xff >> ((block.length * 8) - emBits));
201:
202: for (int i = 0; i != block.length - hLen - sLen - 2; i++) {
203: if (block[i] != 0) {
204: clearBlock(block);
205: return false;
206: }
207: }
208:
209: if (block[block.length - hLen - sLen - 2] != 0x01) {
210: clearBlock(block);
211: return false;
212: }
213:
214: System.arraycopy(block, block.length - sLen - hLen - 1, mDash,
215: mDash.length - sLen, sLen);
216:
217: digest.update(mDash, 0, mDash.length);
218: digest.doFinal(mDash, mDash.length - hLen);
219:
220: for (int i = block.length - hLen - 1, j = mDash.length - hLen; j != mDash.length; i++, j++) {
221: if ((block[i] ^ mDash[j]) != 0) {
222: clearBlock(mDash);
223: clearBlock(block);
224: return false;
225: }
226: }
227:
228: clearBlock(mDash);
229: clearBlock(block);
230:
231: return true;
232: }
233:
234: /**
235: * int to octet string.
236: */
237: private void ItoOSP(int i, byte[] sp) {
238: sp[0] = (byte) (i >>> 24);
239: sp[1] = (byte) (i >>> 16);
240: sp[2] = (byte) (i >>> 8);
241: sp[3] = (byte) (i >>> 0);
242: }
243:
244: /**
245: * mask generator function, as described in PKCS1v2.
246: */
247: private byte[] maskGeneratorFunction1(byte[] Z, int zOff, int zLen,
248: int length) {
249: byte[] mask = new byte[length];
250: byte[] hashBuf = new byte[hLen];
251: byte[] C = new byte[4];
252: int counter = 0;
253:
254: digest.reset();
255:
256: while (counter < (length / hLen)) {
257: ItoOSP(counter, C);
258:
259: digest.update(Z, zOff, zLen);
260: digest.update(C, 0, C.length);
261: digest.doFinal(hashBuf, 0);
262:
263: System.arraycopy(hashBuf, 0, mask, counter * hLen, hLen);
264:
265: counter++;
266: }
267:
268: if ((counter * hLen) < length) {
269: ItoOSP(counter, C);
270:
271: digest.update(Z, zOff, zLen);
272: digest.update(C, 0, C.length);
273: digest.doFinal(hashBuf, 0);
274:
275: System.arraycopy(hashBuf, 0, mask, counter * hLen,
276: mask.length - (counter * hLen));
277: }
278:
279: return mask;
280: }
281: }
|