diff options
Diffstat (limited to 'core/src/main/java/org/spongycastle/crypto/digests/SHA512tDigest.java')
-rw-r--r-- | core/src/main/java/org/spongycastle/crypto/digests/SHA512tDigest.java | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/crypto/digests/SHA512tDigest.java b/core/src/main/java/org/spongycastle/crypto/digests/SHA512tDigest.java new file mode 100644 index 00000000..fc05781f --- /dev/null +++ b/core/src/main/java/org/spongycastle/crypto/digests/SHA512tDigest.java @@ -0,0 +1,227 @@ +package org.spongycastle.crypto.digests; + +import org.spongycastle.util.Memoable; +import org.spongycastle.util.MemoableResetException; +import org.spongycastle.util.Pack; + +/** + * FIPS 180-4 implementation of SHA-512/t + */ +public class SHA512tDigest + extends LongDigest +{ + private int digestLength; // non-final due to old flow analyser. + + private long H1t, H2t, H3t, H4t, H5t, H6t, H7t, H8t; + + /** + * Standard constructor + */ + public SHA512tDigest(int bitLength) + { + if (bitLength >= 512) + { + throw new IllegalArgumentException("bitLength cannot be >= 512"); + } + + if (bitLength % 8 != 0) + { + throw new IllegalArgumentException("bitLength needs to be a multiple of 8"); + } + + if (bitLength == 384) + { + throw new IllegalArgumentException("bitLength cannot be 384 use SHA384 instead"); + } + + this.digestLength = bitLength / 8; + + tIvGenerate(digestLength * 8); + + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SHA512tDigest(SHA512tDigest t) + { + super(t); + + this.digestLength = t.digestLength; + + reset(t); + } + + public SHA512tDigest(byte[] encodedState) + { + this(readDigestLength(encodedState)); + restoreState(encodedState); + } + + private static int readDigestLength(byte[] encodedState) + { + return Pack.bigEndianToInt(encodedState, encodedState.length - 4); + } + + public String getAlgorithmName() + { + return "SHA-512/" + Integer.toString(digestLength * 8); + } + + public int getDigestSize() + { + return digestLength; + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + longToBigEndian(H1, out, outOff, digestLength); + longToBigEndian(H2, out, outOff + 8, digestLength - 8); + longToBigEndian(H3, out, outOff + 16, digestLength - 16); + longToBigEndian(H4, out, outOff + 24, digestLength - 24); + longToBigEndian(H5, out, outOff + 32, digestLength - 32); + longToBigEndian(H6, out, outOff + 40, digestLength - 40); + longToBigEndian(H7, out, outOff + 48, digestLength - 48); + longToBigEndian(H8, out, outOff + 56, digestLength - 56); + + reset(); + + return digestLength; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + /* + * initial hash values use the iv generation algorithm for t. + */ + H1 = H1t; + H2 = H2t; + H3 = H3t; + H4 = H4t; + H5 = H5t; + H6 = H6t; + H7 = H7t; + H8 = H8t; + } + + private void tIvGenerate(int bitLength) + { + H1 = 0x6a09e667f3bcc908L ^ 0xa5a5a5a5a5a5a5a5L; + H2 = 0xbb67ae8584caa73bL ^ 0xa5a5a5a5a5a5a5a5L; + H3 = 0x3c6ef372fe94f82bL ^ 0xa5a5a5a5a5a5a5a5L; + H4 = 0xa54ff53a5f1d36f1L ^ 0xa5a5a5a5a5a5a5a5L; + H5 = 0x510e527fade682d1L ^ 0xa5a5a5a5a5a5a5a5L; + H6 = 0x9b05688c2b3e6c1fL ^ 0xa5a5a5a5a5a5a5a5L; + H7 = 0x1f83d9abfb41bd6bL ^ 0xa5a5a5a5a5a5a5a5L; + H8 = 0x5be0cd19137e2179L ^ 0xa5a5a5a5a5a5a5a5L; + + update((byte)0x53); + update((byte)0x48); + update((byte)0x41); + update((byte)0x2D); + update((byte)0x35); + update((byte)0x31); + update((byte)0x32); + update((byte)0x2F); + + if (bitLength > 100) + { + update((byte)(bitLength / 100 + 0x30)); + bitLength = bitLength % 100; + update((byte)(bitLength / 10 + 0x30)); + bitLength = bitLength % 10; + update((byte)(bitLength + 0x30)); + } + else if (bitLength > 10) + { + update((byte)(bitLength / 10 + 0x30)); + bitLength = bitLength % 10; + update((byte)(bitLength + 0x30)); + } + else + { + update((byte)(bitLength + 0x30)); + } + + finish(); + + H1t = H1; + H2t = H2; + H3t = H3; + H4t = H4; + H5t = H5; + H6t = H6; + H7t = H7; + H8t = H8; + } + + private static void longToBigEndian(long n, byte[] bs, int off, int max) + { + if (max > 0) + { + intToBigEndian((int)(n >>> 32), bs, off, max); + + if (max > 4) + { + intToBigEndian((int)(n & 0xffffffffL), bs, off + 4, max - 4); + } + } + } + + private static void intToBigEndian(int n, byte[] bs, int off, int max) + { + int num = Math.min(4, max); + while (--num >= 0) + { + int shift = 8 * (3 - num); + bs[off + num] = (byte)(n >>> shift); + } + } + + public Memoable copy() + { + return new SHA512tDigest(this); + } + + public void reset(Memoable other) + { + SHA512tDigest t = (SHA512tDigest)other; + + if (this.digestLength != t.digestLength) + { + throw new MemoableResetException("digestLength inappropriate in other"); + } + + super.copyIn(t); + + this.H1t = t.H1t; + this.H2t = t.H2t; + this.H3t = t.H3t; + this.H4t = t.H4t; + this.H5t = t.H5t; + this.H6t = t.H6t; + this.H7t = t.H7t; + this.H8t = t.H8t; + } + + public byte[] getEncodedState() + { + final int baseSize = getEncodedStateSize(); + byte[] encoded = new byte[baseSize + 4]; + populateState(encoded); + Pack.intToBigEndian(digestLength * 8, encoded, baseSize); + return encoded; + } + +} |