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