diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/digests/SM3Digest.java')
-rw-r--r-- | bcprov/src/main/java/org/bouncycastle/crypto/digests/SM3Digest.java | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SM3Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SM3Digest.java new file mode 100644 index 0000000..5e90add --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SM3Digest.java @@ -0,0 +1,333 @@ +package org.bouncycastle.crypto.digests; + +import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; + +/** + * Implementation of Chinese SM3 digest as described at + * http://tools.ietf.org/html/draft-shen-sm3-hash-00 + * and at .... ( Chinese PDF ) + * <p> + * The specification says "process a bit stream", + * but this is written to process bytes in blocks of 4, + * meaning this will process 32-bit word groups. + * But so do also most other digest specifications, + * including the SHA-256 which was a origin for + * this specification. + */ +public class SM3Digest + extends GeneralDigest +{ + private static final int DIGEST_LENGTH = 32; // bytes + private static final int BLOCK_SIZE = 64 / 4; // of 32 bit ints (16 ints) + + private int[] V = new int[DIGEST_LENGTH / 4]; // in 32 bit ints (8 ints) + private int[] inwords = new int[BLOCK_SIZE]; + private int xOff; + + // Work-bufs used within processBlock() + private int[] W = new int[68]; + private int[] W1 = new int[64]; + + // Round constant T for processBlock() which is 32 bit integer rolled left up to (63 MOD 32) bit positions. + private static final int[] T = new int[64]; + + static + { + for (int i = 0; i < 16; ++i) + { + int t = 0x79CC4519; + T[i] = (t << i) | (t >>> (32 - i)); + } + for (int i = 16; i < 64; ++i) + { + int n = i % 32; + int t = 0x7A879D8A; + T[i] = (t << n) | (t >>> (32 - n)); + } + } + + + /** + * Standard constructor + */ + public SM3Digest() + { + reset(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public SM3Digest(SM3Digest t) + { + super(t); + + copyIn(t); + } + + private void copyIn(SM3Digest t) + { + System.arraycopy(t.V, 0, this.V, 0, this.V.length); + System.arraycopy(t.inwords, 0, this.inwords, 0, this.inwords.length); + xOff = t.xOff; + } + + public String getAlgorithmName() + { + return "SM3"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + + public Memoable copy() + { + return new SM3Digest(this); + } + + public void reset(Memoable other) + { + SM3Digest d = (SM3Digest)other; + + super.copyIn(d); + copyIn(d); + } + + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + this.V[0] = 0x7380166F; + this.V[1] = 0x4914B2B9; + this.V[2] = 0x172442D7; + this.V[3] = 0xDA8A0600; + this.V[4] = 0xA96F30BC; + this.V[5] = 0x163138AA; + this.V[6] = 0xE38DEE4D; + this.V[7] = 0xB0FB0E4E; + + this.xOff = 0; + } + + + public int doFinal(byte[] out, + int outOff) + { + finish(); + + Pack.intToBigEndian(this.V[0], out, outOff + 0); + Pack.intToBigEndian(this.V[1], out, outOff + 4); + Pack.intToBigEndian(this.V[2], out, outOff + 8); + Pack.intToBigEndian(this.V[3], out, outOff + 12); + Pack.intToBigEndian(this.V[4], out, outOff + 16); + Pack.intToBigEndian(this.V[5], out, outOff + 20); + Pack.intToBigEndian(this.V[6], out, outOff + 24); + Pack.intToBigEndian(this.V[7], out, outOff + 28); + + reset(); + + return DIGEST_LENGTH; + } + + + protected void processWord(byte[] in, + int inOff) + { + // Note: Inlined for performance + // this.inwords[xOff] = Pack.bigEndianToInt(in, inOff); + int n = (((in[inOff] & 0xff) << 24) | + ((in[++inOff] & 0xff) << 16) | + ((in[++inOff] & 0xff) << 8) | + ((in[++inOff] & 0xff))); + + this.inwords[this.xOff] = n; + ++this.xOff; + + if (this.xOff >= 16) + { + processBlock(); + } + } + + protected void processLength(long bitLength) + { + if (this.xOff > (BLOCK_SIZE - 2)) + { + // xOff == 15 --> can't fit the 64 bit length field at tail.. + this.inwords[this.xOff] = 0; // fill with zero + ++this.xOff; + + processBlock(); + } + // Fill with zero words, until reach 2nd to last slot + while (this.xOff < (BLOCK_SIZE - 2)) + { + this.inwords[this.xOff] = 0; + ++this.xOff; + } + + // Store input data length in BITS + this.inwords[this.xOff++] = (int)(bitLength >>> 32); + this.inwords[this.xOff++] = (int)(bitLength); + } + +/* + +3.4.2. Constants + + + Tj = 79cc4519 when 0 < = j < = 15 + Tj = 7a879d8a when 16 < = j < = 63 + +3.4.3. Boolean function + + + FFj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15 + = (X AND Y) OR (X AND Z) OR (Y AND Z) when 16 < = j < = 63 + + GGj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15 + = (X AND Y) OR (NOT X AND Z) when 16 < = j < = 63 + + The X, Y, Z in the fomular are words!GBP + +3.4.4. Permutation function + + + P0(X) = X XOR (X <<< 9) XOR (X <<< 17) ## ROLL, not SHIFT + P1(X) = X XOR (X <<< 15) XOR (X <<< 23) ## ROLL, not SHIFT + + The X in the fomular are a word. + +---------- + +Each ROLL converted to Java expression: + +ROLL 9 : ((x << 9) | (x >>> (32-9)))) +ROLL 17 : ((x << 17) | (x >>> (32-17))) +ROLL 15 : ((x << 15) | (x >>> (32-15))) +ROLL 23 : ((x << 23) | (x >>> (32-23))) + + */ + + private int P0(final int x) + { + final int r9 = ((x << 9) | (x >>> (32 - 9))); + final int r17 = ((x << 17) | (x >>> (32 - 17))); + return (x ^ r9 ^ r17); + } + + private int P1(final int x) + { + final int r15 = ((x << 15) | (x >>> (32 - 15))); + final int r23 = ((x << 23) | (x >>> (32 - 23))); + return (x ^ r15 ^ r23); + } + + private int FF0(final int x, final int y, final int z) + { + return (x ^ y ^ z); + } + + private int FF1(final int x, final int y, final int z) + { + return ((x & y) | (x & z) | (y & z)); + } + + private int GG0(final int x, final int y, final int z) + { + return (x ^ y ^ z); + } + + private int GG1(final int x, final int y, final int z) + { + return ((x & y) | ((~x) & z)); + } + + + protected void processBlock() + { + for (int j = 0; j < 16; ++j) + { + this.W[j] = this.inwords[j]; + } + for (int j = 16; j < 68; ++j) + { + int wj3 = this.W[j - 3]; + int r15 = ((wj3 << 15) | (wj3 >>> (32 - 15))); + int wj13 = this.W[j - 13]; + int r7 = ((wj13 << 7) | (wj13 >>> (32 - 7))); + this.W[j] = P1(this.W[j - 16] ^ this.W[j - 9] ^ r15) ^ r7 ^ this.W[j - 6]; + } + for (int j = 0; j < 64; ++j) + { + this.W1[j] = this.W[j] ^ this.W[j + 4]; + } + + int A = this.V[0]; + int B = this.V[1]; + int C = this.V[2]; + int D = this.V[3]; + int E = this.V[4]; + int F = this.V[5]; + int G = this.V[6]; + int H = this.V[7]; + + + for (int j = 0; j < 16; ++j) + { + int a12 = ((A << 12) | (A >>> (32 - 12))); + int s1_ = a12 + E + T[j]; + int SS1 = ((s1_ << 7) | (s1_ >>> (32 - 7))); + int SS2 = SS1 ^ a12; + int TT1 = FF0(A, B, C) + D + SS2 + this.W1[j]; + int TT2 = GG0(E, F, G) + H + SS1 + this.W[j]; + D = C; + C = ((B << 9) | (B >>> (32 - 9))); + B = A; + A = TT1; + H = G; + G = ((F << 19) | (F >>> (32 - 19))); + F = E; + E = P0(TT2); + } + + // Different FF,GG functions on rounds 16..63 + for (int j = 16; j < 64; ++j) + { + int a12 = ((A << 12) | (A >>> (32 - 12))); + int s1_ = a12 + E + T[j]; + int SS1 = ((s1_ << 7) | (s1_ >>> (32 - 7))); + int SS2 = SS1 ^ a12; + int TT1 = FF1(A, B, C) + D + SS2 + this.W1[j]; + int TT2 = GG1(E, F, G) + H + SS1 + this.W[j]; + D = C; + C = ((B << 9) | (B >>> (32 - 9))); + B = A; + A = TT1; + H = G; + G = ((F << 19) | (F >>> (32 - 19))); + F = E; + E = P0(TT2); + } + + this.V[0] ^= A; + this.V[1] ^= B; + this.V[2] ^= C; + this.V[3] ^= D; + this.V[4] ^= E; + this.V[5] ^= F; + this.V[6] ^= G; + this.V[7] ^= H; + + this.xOff = 0; + } +} |