FileDocCategorySizeDatePackage
PSSSigner.javaAPI DocAndroid 1.5 API8090Wed May 06 22:41:06 BST 2009org.bouncycastle.crypto.signers

PSSSigner

public class PSSSigner extends Object implements org.bouncycastle.crypto.Signer
RSA-PSS as described in PKCS# 1 v 2.1.

Note: the usual value for the salt length is the number of bytes in the hash function.

Fields Summary
public static final byte
TRAILER_IMPLICIT
private org.bouncycastle.crypto.Digest
digest
private org.bouncycastle.crypto.AsymmetricBlockCipher
cipher
private SecureRandom
random
private int
hLen
private int
sLen
private int
emBits
private byte[]
salt
private byte[]
mDash
private byte[]
block
private byte
trailer
Constructors Summary
public PSSSigner(org.bouncycastle.crypto.AsymmetricBlockCipher cipher, org.bouncycastle.crypto.Digest digest, int sLen)
basic constructor

param
cipher the assymetric cipher to use.
param
digest the digest to use.
param
sLen the length of the salt to use (in bytes).


                                   
     
           
                          
                             
    
        this(cipher, digest, sLen, TRAILER_IMPLICIT);
    
public PSSSigner(org.bouncycastle.crypto.AsymmetricBlockCipher cipher, org.bouncycastle.crypto.Digest digest, int sLen, byte trailer)

        this.cipher = cipher;
        this.digest = digest;
        this.hLen = digest.getDigestSize();
        this.sLen = sLen;
        this.salt = new byte[sLen];
        this.mDash = new byte[8 + sLen + hLen];
        this.trailer = trailer;
    
Methods Summary
private voidItoOSP(int i, byte[] sp)
int to octet string.

        sp[0] = (byte)(i >>> 24);
        sp[1] = (byte)(i >>> 16);
        sp[2] = (byte)(i >>> 8);
        sp[3] = (byte)(i >>> 0);
    
private voidclearBlock(byte[] block)
clear possible sensitive data

        for (int i = 0; i != block.length; i++)
        {
            block[i] = 0;
        }
    
public byte[]generateSignature()
generate a signature for the message we've been loaded with using the key we were initialised with.

        if (emBits < (8 * hLen + 8 * sLen + 9))
        {
            throw new DataLengthException("encoding error");
        }

        digest.doFinal(mDash, mDash.length - hLen - sLen);

        if (sLen != 0)
        {
            random.nextBytes(salt);

            System.arraycopy(salt, 0, mDash, mDash.length - sLen, sLen);
        }

        byte[]  h = new byte[hLen];

        digest.update(mDash, 0, mDash.length);

        digest.doFinal(h, 0);

        block[block.length - sLen - 1 - hLen - 1] = 0x01;
        System.arraycopy(salt, 0, block, block.length - sLen - hLen - 1, sLen);

        byte[] dbMask = maskGeneratorFunction1(h, 0, h.length, block.length - hLen - 1);
        for (int i = 0; i != dbMask.length; i++)
        {
            block[i] ^= dbMask[i];
        }

        block[0] &= (0xff >> ((block.length * 8) - emBits));

        System.arraycopy(h, 0, block, block.length - hLen - 1, hLen);

        block[block.length - 1] = trailer;

        byte[]  b = cipher.processBlock(block, 0, block.length);

        clearBlock(block);

        return b;
    
public voidinit(boolean forSigning, org.bouncycastle.crypto.CipherParameters param)

        RSAKeyParameters  kParam = null;

        if (param instanceof ParametersWithRandom)
        {
            ParametersWithRandom    p = (ParametersWithRandom)param;

            kParam = (RSAKeyParameters)p.getParameters();
            random = p.getRandom();
        }
        else
        {
            kParam = (RSAKeyParameters)param;
            if (forSigning)
            {
                random = new SecureRandom();
            }
        }

        cipher.init(forSigning, kParam);

        emBits = kParam.getModulus().bitLength() - 1;

        block = new byte[(emBits + 7) / 8];

        reset();
    
private byte[]maskGeneratorFunction1(byte[] Z, int zOff, int zLen, int length)
mask generator function, as described in PKCS1v2.

        byte[]  mask = new byte[length];
        byte[]  hashBuf = new byte[hLen];
        byte[]  C = new byte[4];
        int     counter = 0;

        digest.reset();

        while (counter < (length / hLen))
        {
            ItoOSP(counter, C);

            digest.update(Z, zOff, zLen);
            digest.update(C, 0, C.length);
            digest.doFinal(hashBuf, 0);

            System.arraycopy(hashBuf, 0, mask, counter * hLen, hLen);
            
            counter++;
        }

        if ((counter * hLen) < length)
        {
            ItoOSP(counter, C);

            digest.update(Z, zOff, zLen);
            digest.update(C, 0, C.length);
            digest.doFinal(hashBuf, 0);

            System.arraycopy(hashBuf, 0, mask, counter * hLen, mask.length - (counter * hLen));
        }

        return mask;
    
public voidreset()
reset the internal state

        digest.reset();
    
public voidupdate(byte b)
update the internal digest with the byte b

        digest.update(b);
    
public voidupdate(byte[] in, int off, int len)
update the internal digest with the byte array in

        digest.update(in, off, len);
    
public booleanverifySignature(byte[] signature)
return true if the internal state represents the signature described in the passed in array.

        if (emBits < (8 * hLen + 8 * sLen + 9))
        {
            return false;
        }

        digest.doFinal(mDash, mDash.length - hLen - sLen);

        try
        {
            byte[] b = cipher.processBlock(signature, 0, signature.length);
            System.arraycopy(b, 0, block, block.length - b.length, b.length);
        }
        catch (Exception e)
        {
            return false;
        }

        if (block[block.length - 1] != trailer)
        {
            clearBlock(block);
            return false;
        }

        byte[] dbMask = maskGeneratorFunction1(block, block.length - hLen - 1, hLen, block.length - hLen - 1);

        for (int i = 0; i != dbMask.length; i++)
        {
            block[i] ^= dbMask[i];
        }

        block[0] &= (0xff >> ((block.length * 8) - emBits));

        for (int i = 0; i != block.length - hLen - sLen - 2; i++)
        {
            if (block[i] != 0)
            {
                clearBlock(block);
                return false;
            }
        }

        if (block[block.length - hLen - sLen - 2] != 0x01)
        {
            clearBlock(block);
            return false;
        }

        System.arraycopy(block, block.length - sLen - hLen - 1, mDash, mDash.length - sLen, sLen);

        digest.update(mDash, 0, mDash.length);
        digest.doFinal(mDash, mDash.length - hLen);

        for (int i = block.length - hLen - 1, j = mDash.length - hLen;
                                                 j != mDash.length; i++, j++)
        {
            if ((block[i] ^ mDash[j]) != 0)
            {
                clearBlock(mDash);
                clearBlock(block);
                return false;
            }
        }

        clearBlock(mDash);
        clearBlock(block);

        return true;