diff options
Diffstat (limited to 'libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CombinedHash.java')
-rw-r--r-- | libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CombinedHash.java | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CombinedHash.java b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CombinedHash.java new file mode 100644 index 000000000..b32ad91ee --- /dev/null +++ b/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/tls/CombinedHash.java @@ -0,0 +1,135 @@ +package org.spongycastle.crypto.tls; + +import org.spongycastle.crypto.Digest; + +/** + * A combined hash, which implements md5(m) || sha1(m). + */ +class CombinedHash + implements TlsHandshakeHash +{ + protected TlsContext context; + protected Digest md5; + protected Digest sha1; + + CombinedHash() + { + this.md5 = TlsUtils.createHash(HashAlgorithm.md5); + this.sha1 = TlsUtils.createHash(HashAlgorithm.sha1); + } + + CombinedHash(CombinedHash t) + { + this.context = t.context; + this.md5 = TlsUtils.cloneHash(HashAlgorithm.md5, t.md5); + this.sha1 = TlsUtils.cloneHash(HashAlgorithm.sha1, t.sha1); + } + + public void init(TlsContext context) + { + this.context = context; + } + + public TlsHandshakeHash notifyPRFDetermined() + { + return this; + } + + public void trackHashAlgorithm(short hashAlgorithm) + { + throw new IllegalStateException("CombinedHash only supports calculating the legacy PRF for handshake hash"); + } + + public void sealHashAlgorithms() + { + } + + public TlsHandshakeHash stopTracking() + { + return new CombinedHash(this); + } + + public Digest forkPRFHash() + { + return new CombinedHash(this); + } + + public byte[] getFinalHash(short hashAlgorithm) + { + throw new IllegalStateException("CombinedHash doesn't support multiple hashes"); + } + + /** + * @see org.spongycastle.crypto.Digest#getAlgorithmName() + */ + public String getAlgorithmName() + { + return md5.getAlgorithmName() + " and " + sha1.getAlgorithmName(); + } + + /** + * @see org.spongycastle.crypto.Digest#getDigestSize() + */ + public int getDigestSize() + { + return md5.getDigestSize() + sha1.getDigestSize(); + } + + /** + * @see org.spongycastle.crypto.Digest#update(byte) + */ + public void update(byte in) + { + md5.update(in); + sha1.update(in); + } + + /** + * @see org.spongycastle.crypto.Digest#update(byte[], int, int) + */ + public void update(byte[] in, int inOff, int len) + { + md5.update(in, inOff, len); + sha1.update(in, inOff, len); + } + + /** + * @see org.spongycastle.crypto.Digest#doFinal(byte[], int) + */ + public int doFinal(byte[] out, int outOff) + { + if (context != null && TlsUtils.isSSL(context)) + { + ssl3Complete(md5, SSL3Mac.IPAD, SSL3Mac.OPAD, 48); + ssl3Complete(sha1, SSL3Mac.IPAD, SSL3Mac.OPAD, 40); + } + + int i1 = md5.doFinal(out, outOff); + int i2 = sha1.doFinal(out, outOff + i1); + return i1 + i2; + } + + /** + * @see org.spongycastle.crypto.Digest#reset() + */ + public void reset() + { + md5.reset(); + sha1.reset(); + } + + protected void ssl3Complete(Digest d, byte[] ipad, byte[] opad, int padLength) + { + byte[] master_secret = context.getSecurityParameters().masterSecret; + + d.update(master_secret, 0, master_secret.length); + d.update(ipad, 0, padLength); + + byte[] tmp = new byte[d.getDigestSize()]; + d.doFinal(tmp, 0); + + d.update(master_secret, 0, master_secret.length); + d.update(opad, 0, padLength); + d.update(tmp, 0, tmp.length); + } +} |