summaryrefslogtreecommitdiffstats
path: root/bcprov/src/main/java/org/bouncycastle/crypto/tls/DeferredHash.java
blob: e8c76e6518e6dff800afda74c5e344182195ff5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package org.bouncycastle.crypto.tls;

import java.io.ByteArrayOutputStream;

import org.bouncycastle.crypto.Digest;

/**
 * Buffers input until the hash algorithm is determined.
 */
class DeferredHash
    implements TlsHandshakeHash
{

    protected TlsContext context;

    private ByteArrayOutputStream buf = new ByteArrayOutputStream();
    private int prfAlgorithm = -1;
    private Digest hash = null;

    DeferredHash()
    {
        this.buf = new ByteArrayOutputStream();
        this.hash = null;
    }

    private DeferredHash(Digest hash)
    {
        this.buf = null;
        this.hash = hash;
    }

    public void init(TlsContext context)
    {
        this.context = context;
    }

    public TlsHandshakeHash commit()
    {

        int prfAlgorithm = context.getSecurityParameters().getPrfAlgorithm();

        Digest prfHash = TlsUtils.createPRFHash(prfAlgorithm);

        byte[] data = buf.toByteArray();
        prfHash.update(data, 0, data.length);

        if (prfHash instanceof TlsHandshakeHash)
        {
            TlsHandshakeHash tlsPRFHash = (TlsHandshakeHash)prfHash;
            tlsPRFHash.init(context);
            return tlsPRFHash.commit();
        }

        this.prfAlgorithm = prfAlgorithm;
        this.hash = prfHash;
        this.buf = null;

        return this;
    }

    public TlsHandshakeHash fork()
    {
        checkHash();
        return new DeferredHash(TlsUtils.clonePRFHash(prfAlgorithm, hash));
    }

    public String getAlgorithmName()
    {
        checkHash();
        return hash.getAlgorithmName();
    }

    public int getDigestSize()
    {
        checkHash();
        return hash.getDigestSize();
    }

    public void update(byte input)
    {
        if (hash == null)
        {
            buf.write(input);
        }
        else
        {
            hash.update(input);
        }
    }

    public void update(byte[] input, int inOff, int len)
    {
        if (hash == null)
        {
            buf.write(input, inOff, len);
        }
        else
        {
            hash.update(input, inOff, len);
        }
    }

    public int doFinal(byte[] output, int outOff)
    {
        checkHash();
        return hash.doFinal(output, outOff);
    }

    public void reset()
    {
        if (hash == null)
        {
            buf.reset();
        }
        else
        {
            hash.reset();
        }
    }

    protected void checkHash()
    {
        if (hash == null)
        {
            throw new IllegalStateException("No hash algorithm has been set");
        }
    }
}