Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.bouncycastle.crypto.prng.drbg;
  
A SP800-90A CTR DRBG.
 
 public class CTRSP800DRBG
     implements SP80090DRBG
 {
     private static final long       TDEA_RESEED_MAX = 1L << (32 - 1);
     private static final long       AES_RESEED_MAX = 1L << (48 - 1);
     private static final int        TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
     private static final int        AES_MAX_BITS_REQUEST = 1 << (19 - 1);
 
     private EntropySource          _entropySource;
     private BlockCipher           _engine;
     private int                   _keySizeInBits;
     private int                   _seedLength;
     
     // internal state
     private byte[]                _Key;
     private byte[]                _V;
     private long                  _reseedCounter = 0;
     private boolean               _isTDEA = false;

    
Construct a SP800-90A CTR DRBG.

Minimum entropy requirement is the security strength requested.

Parameters:
engine underlying block cipher to use to support DRBG
keySizeInBits size of the key to use with the block cipher.
securityStrength security strength required (in bits)
entropySource source of entropy to use for seeding/reseeding.
personalizationString personalization string to distinguish this DRBG (may be null).
nonce nonce to further distinguish this DRBG (may be null).
 
     public CTRSP800DRBG(BlockCipher engineint keySizeInBitsint securityStrengthEntropySource entropySourcebyte[] personalizationStringbyte[] nonce)
     {
          = entropySource;
          = engine;     
         
          = keySizeInBits;
          = keySizeInBits + engine.getBlockSize() * 8;
          = isTDEA(engine);
 
         if (securityStrength > 256)
         {
             throw new IllegalArgumentException("Requested security strength is not supported by the derivation function");
         }
 
         if (getMaxSecurityStrength(enginekeySizeInBits) < securityStrength)
         {
             throw new IllegalArgumentException("Requested security strength is not supported by block cipher and key size");
         }
 
         if (entropySource.entropySize() < securityStrength)
         {
             throw new IllegalArgumentException("Not enough entropy for security strength required");
         }
 
         byte[] entropy = entropySource.getEntropy();  // Get_entropy_input
 
         CTR_DRBG_Instantiate_algorithm(entropynoncepersonalizationString);
     }
 
     private void CTR_DRBG_Instantiate_algorithm(byte[] entropybyte[] nonce,
             byte[] personalisationString)
     {
         byte[] seedMaterial = Arrays.concatenate(entropynoncepersonalisationString);
         byte[] seed = Block_Cipher_df(seedMaterial);
 
         int outlen = .getBlockSize();
 
          = new byte[( + 7) / 8];
          = new byte[outlen];
 
          // _Key & _V are modified by this call
         CTR_DRBG_Update(seed); 
 
          = 1;
     }
 
     private void CTR_DRBG_Update(byte[] seedbyte[] keybyte[] v)
     {
         byte[] temp = new byte[seed.length];
         byte[] outputBlock = new byte[.getBlockSize()];
         
         int i=0;
         int outLen = .getBlockSize();
 
         .init(truenew KeyParameter(expandKey(key)));
         while (i*outLen < seed.length)
         {
            addOneTo(v);
            .processBlock(v, 0, outputBlock, 0);
            int bytesToCopy = ((temp.length - i * outLen) > outLen)
                    ? outLen : (temp.length - i * outLen);
            
            System.arraycopy(outputBlock, 0, tempi * outLenbytesToCopy);
            ++i;
        }
        XOR(tempseedtemp, 0);
        System.arraycopy(temp, 0, key, 0, key.length);
        System.arraycopy(tempkey.lengthv, 0, v.length);
    }
    
    private void CTR_DRBG_Reseed_algorithm(EntropySource entropybyte[] additionalInput
    {
        byte[] seedMaterial = Arrays.concatenate(entropy.getEntropy(), additionalInput);
        seedMaterial = Block_Cipher_df(seedMaterial);
        CTR_DRBG_Update(seedMaterial);
         = 1;
    }
    private void XOR(byte[] outbyte[] abyte[] bint bOff)
    {
        for (int i=0; iout.lengthi++) 
        {
            out[i] = (byte)(a[i] ^ b[i+bOff]);
        }
    }
    
    private void addOneTo(byte[] longer)
    {
        int carry = 1;
        for (int i = 1; i <= longer.lengthi++) // warning
        {
            int res = (longer[longer.length - i] & 0xff) + carry;
            carry = (res > 0xff) ? 1 : 0;
            longer[longer.length - i] = (byte)res;
        }
    } 
    
    // -- Internal state migration ---
    
    private static final byte[] K_BITS = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
    // 1. If (number_of_bits_to_return > max_number_of_bits), then return an
    // ERROR_FLAG.
    // 2. L = len (input_string)/8.
    // 3. N = number_of_bits_to_return/8.
    // Comment: L is the bitstring represention of
    // the integer resulting from len (input_string)/8.
    // L shall be represented as a 32-bit integer.
    //
    // Comment : N is the bitstring represention of
    // the integer resulting from
    // number_of_bits_to_return/8. N shall be
    // represented as a 32-bit integer.
    //
    // 4. S = L || N || input_string || 0x80.
    // 5. While (len (S) mod outlen)
    // Comment : Pad S with zeros, if necessary.
    // 0, S = S || 0x00.
    //
    // Comment : Compute the starting value.
    // 6. temp = the Null string.
    // 7. i = 0.
    // 8. K = Leftmost keylen bits of 0x00010203...1D1E1F.
    // 9. While len (temp) < keylen + outlen, do
    //
    // IV = i || 0outlen - len (i).
    //
    // 9.1
    //
    // temp = temp || BCC (K, (IV || S)).
    //
    // 9.2
    //
    // i = i + 1.
    //
    // 9.3
    //
    // Comment : i shall be represented as a 32-bit
    // integer, i.e., len (i) = 32.
    //
    // Comment: The 32-bit integer represenation of
    // i is padded with zeros to outlen bits.
    //
    // Comment: Compute the requested number of
    // bits.
    //
    // 10. K = Leftmost keylen bits of temp.
    //
    // 11. X = Next outlen bits of temp.
    //
    // 12. temp = the Null string.
    //
    // 13. While len (temp) < number_of_bits_to_return, do
    //
    // 13.1 X = Block_Encrypt (K, X).
    //
    // 13.2 temp = temp || X.
    //
    // 14. requested_bits = Leftmost number_of_bits_to_return of temp.
    //
    // 15. Return SUCCESS and requested_bits.
    private byte[] Block_Cipher_df(byte[] inputStringint bitLength)
    {
        int outLen = .getBlockSize();
        int L = inputString.length// already in bytes
        int N = bitLength / 8;
        // 4 S = L || N || inputstring || 0x80
        int sLen = 4 + 4 + L + 1;
        int blockLen = ((sLen + outLen - 1) / outLen) * outLen;
        byte[] S = new byte[blockLen];
        copyIntToByteArray(SL, 0);
        copyIntToByteArray(SN, 4);
        System.arraycopy(inputString, 0, S, 8, L);
        S[8 + L] = (byte)0x80;
        // S already padded with zeros
        byte[] temp = new byte[ / 8 + outLen];
        byte[] bccOut = new byte[outLen];
        byte[] IV = new byte[outLen]; 
        
        int i = 0;
        byte[] K = new byte[ / 8];
        System.arraycopy(, 0, K, 0, K.length);
        while (i*outLen*8 <  + outLen *8)
        {
            copyIntToByteArray(IVi, 0);
            BCC(bccOutKIVS);
            int bytesToCopy = ((temp.length - i * outLen) > outLen)
                    ? outLen
                    : (temp.length - i * outLen);
            
            System.arraycopy(bccOut, 0, tempi * outLenbytesToCopy);
            ++i;
        }
        byte[] X = new byte[outLen];
        System.arraycopy(temp, 0, K, 0, K.length);
        System.arraycopy(tempK.lengthX, 0, X.length);
        temp = new byte[bitLength / 2];
        i = 0;
        .init(truenew KeyParameter(expandKey(K)));
        while (i * outLen < temp.length)
        {
            .processBlock(X, 0, X, 0);
            int bytesToCopy = ((temp.length - i * outLen) > outLen)
                    ? outLen
                    : (temp.length - i * outLen);
            System.arraycopy(X, 0, tempi * outLenbytesToCopy);
            i++;
        }
        return temp;
    }
    /*
    * 1. chaining_value = 0^outlen    
    *    . Comment: Set the first chaining value to outlen zeros.
    * 2. n = len (data)/outlen.
    * 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits 
    *    each, forming block(1) to block(n). 
    * 4. For i = 1 to n do
    * 4.1 input_block = chaining_value ^ block(i) .
    * 4.2 chaining_value = Block_Encrypt (Key, input_block).
    * 5. output_block = chaining_value.
    * 6. Return output_block. 
     */
    private void BCC(byte[] bccOutbyte[] kbyte[] iVbyte[] data)
    {
        int outlen = .getBlockSize();
        byte[] chainingValue = new byte[outlen]; // initial values = 0
        int n = data.length / outlen;
        byte[] inputBlock = new byte[outlen];
        .init(truenew KeyParameter(expandKey(k)));
        .processBlock(iV, 0, chainingValue, 0);
        for (int i = 0; i < ni++)
        {
            XOR(inputBlockchainingValuedatai*outlen);
            .processBlock(inputBlock, 0, chainingValue, 0);
        }
        System.arraycopy(chainingValue, 0, bccOut, 0, bccOut.length);
    }
    private void copyIntToByteArray(byte[] bufint valueint offSet)
    {
        buf[offSet + 0] = ((byte)(value >> 24));
        buf[offSet + 1] = ((byte)(value >> 16));
        buf[offSet + 2] = ((byte)(value >> 8));
        buf[offSet + 3] = ((byte)(value));
    }

    
Return the block size (in bits) of the DRBG.

Returns:
the number of bits produced on each internal round of the DRBG.
    public int getBlockSize()
    {
        return . * 8;
    }

    
Populate a passed in array with random data.

Parameters:
output output array for generated bits.
additionalInput additional input to be added to the DRBG in this step.
predictionResistant true if a reseed should be forced, false otherwise.
Returns:
number of bits generated, -1 if a reseed required.
    public int generate(byte[] outputbyte[] additionalInputboolean predictionResistant)
    {
        if ()
        {
            if ( > )
            {
                return -1;
            }
            if (Utils.isTooLarge(output / 8))
            {
                throw new IllegalArgumentException("Number of bits per request limited to " + );
            }
        }
        else
        {
            if ( > )
            {
                return -1;
            }
            if (Utils.isTooLarge(output / 8))
            {
                throw new IllegalArgumentException("Number of bits per request limited to " + );
            }
        }
        if (predictionResistant)
        {
            CTR_DRBG_Reseed_algorithm(additionalInput);
            additionalInput = null;
        }
        if (additionalInput != null)
        {
            additionalInput = Block_Cipher_df(additionalInput);
            CTR_DRBG_Update(additionalInput);
        }
        else
        {
            additionalInput = new byte[];
        }
        byte[] out = new byte[.];
        .init(truenew KeyParameter(expandKey()));
        for (int i = 0; i <= output.length / out.lengthi++)
        {
            int bytesToCopy = ((output.length - i * out.length) > out.length)
                    ? out.length
                    : (output.length - i * .);
            if (bytesToCopy != 0)
            {
                addOneTo();
                .processBlock(, 0, out, 0);
                System.arraycopy(out, 0, outputi * out.lengthbytesToCopy);
            }
        }
        CTR_DRBG_Update(additionalInput);
        ++;
        return output.length * 8;
    }

    
Reseed the DRBG.

Parameters:
additionalInput additional input to be added to the DRBG in this step.
    public void reseed(byte[] additionalInput)
    {
        CTR_DRBG_Reseed_algorithm(additionalInput);
    }
    private boolean isTDEA(BlockCipher cipher)
    {
        return cipher.getAlgorithmName().equals("DESede") || cipher.getAlgorithmName().equals("TDEA");
    }
    private int getMaxSecurityStrength(BlockCipher cipherint keySizeInBits)
    {
        if (isTDEA(cipher) && keySizeInBits == 168)
        {
            return 112;
        }
        if (cipher.getAlgorithmName().equals("AES"))
        {
            return keySizeInBits;
        }
        return -1;
    }
    byte[] expandKey(byte[] key)
    {
        if ()
        {
            // expand key to 192 bits.
            byte[] tmp = new byte[24];
            padKey(key, 0, tmp, 0);
            padKey(key, 7, tmp, 8);
            padKey(key, 14, tmp, 16);
            return tmp;
        }
        else
        {
            return key;
        }
    }

    
Pad out a key for TDEA, setting odd parity for each byte.

Parameters:
keyMaster
keyOff
tmp
tmpOff
    private void padKey(byte[] keyMasterint keyOffbyte[] tmpint tmpOff)
    {
        tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
        tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >>> 1));
        tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >>> 2));
        tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >>> 3));
        tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >>> 4));
        tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >>> 5));
        tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >>> 6));
        tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
        for (int i = tmpOffi <= tmpOff + 7; i++)
        {
            int b = tmp[i];
            tmp[i] = (byte)((b & 0xfe) |
                            ((((b >> 1) ^
                            (b >> 2) ^
                            (b >> 3) ^
                            (b >> 4) ^
                            (b >> 5) ^
                            (b >> 6) ^
                            (b >> 7)) ^ 0x01) & 0x01));
        }
    }
New to GrepCode? Check out our FAQ X