1package org.bouncycastle.crypto.generators; 2 3import org.bouncycastle.crypto.DataLengthException; 4import org.bouncycastle.crypto.DerivationFunction; 5import org.bouncycastle.crypto.DerivationParameters; 6import org.bouncycastle.crypto.Digest; 7import org.bouncycastle.crypto.params.ISO18033KDFParameters; 8import org.bouncycastle.crypto.params.KDFParameters; 9 10/** 11 * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033 12 * <br> 13 * This implementation is based on ISO 18033/P1363a. 14 */ 15public class BaseKDFBytesGenerator 16 implements DerivationFunction 17{ 18 private int counterStart; 19 private Digest digest; 20 private byte[] shared; 21 private byte[] iv; 22 23 /** 24 * Construct a KDF Parameters generator. 25 * <p> 26 * @param counterStart value of counter. 27 * @param digest the digest to be used as the source of derived keys. 28 */ 29 protected BaseKDFBytesGenerator( 30 int counterStart, 31 Digest digest) 32 { 33 this.counterStart = counterStart; 34 this.digest = digest; 35 } 36 37 public void init( 38 DerivationParameters param) 39 { 40 if (param instanceof KDFParameters) 41 { 42 KDFParameters p = (KDFParameters)param; 43 44 shared = p.getSharedSecret(); 45 iv = p.getIV(); 46 } 47 else if (param instanceof ISO18033KDFParameters) 48 { 49 ISO18033KDFParameters p = (ISO18033KDFParameters)param; 50 51 shared = p.getSeed(); 52 iv = null; 53 } 54 else 55 { 56 throw new IllegalArgumentException("KDF parameters required for KDF2Generator"); 57 } 58 } 59 60 /** 61 * return the underlying digest. 62 */ 63 public Digest getDigest() 64 { 65 return digest; 66 } 67 68 /** 69 * fill len bytes of the output buffer with bytes generated from 70 * the derivation function. 71 * 72 * @throws IllegalArgumentException if the size of the request will cause an overflow. 73 * @throws DataLengthException if the out buffer is too small. 74 */ 75 public int generateBytes( 76 byte[] out, 77 int outOff, 78 int len) 79 throws DataLengthException, IllegalArgumentException 80 { 81 if ((out.length - len) < outOff) 82 { 83 throw new DataLengthException("output buffer too small"); 84 } 85 86 long oBytes = len; 87 int outLen = digest.getDigestSize(); 88 89 // 90 // this is at odds with the standard implementation, the 91 // maximum value should be hBits * (2^32 - 1) where hBits 92 // is the digest output size in bits. We can't have an 93 // array with a long index at the moment... 94 // 95 if (oBytes > ((2L << 32) - 1)) 96 { 97 throw new IllegalArgumentException("Output length too large"); 98 } 99 100 int cThreshold = (int)((oBytes + outLen - 1) / outLen); 101 102 byte[] dig = null; 103 104 dig = new byte[digest.getDigestSize()]; 105 106 int counter = counterStart; 107 108 for (int i = 0; i < cThreshold; i++) 109 { 110 digest.update(shared, 0, shared.length); 111 112 digest.update((byte)(counter >> 24)); 113 digest.update((byte)(counter >> 16)); 114 digest.update((byte)(counter >> 8)); 115 digest.update((byte)counter); 116 117 if (iv != null) 118 { 119 digest.update(iv, 0, iv.length); 120 } 121 122 digest.doFinal(dig, 0); 123 124 if (len > outLen) 125 { 126 System.arraycopy(dig, 0, out, outOff, outLen); 127 outOff += outLen; 128 len -= outLen; 129 } 130 else 131 { 132 System.arraycopy(dig, 0, out, outOff, len); 133 } 134 135 counter++; 136 } 137 138 digest.reset(); 139 140 return len; 141 } 142} 143