📄 uhash32.java
字号:
throw new RuntimeException("KDF for L3Key2 reached limit"); } L1Hash32 mac = new L1Hash32(); mac.init(k1, k2, k31, k32); l1hash[i] = mac; } } public void update(byte b) { for (int i = 0; i < streams; i++) { l1hash[i].update(b); } } public void update(byte[] b, int offset, int len) { for (int i = 0; i < len; i++) { this.update(b[offset + i]); } } public byte[] digest() { byte[] result = new byte[UMac32.OUTPUT_LEN]; for (int i = 0; i < streams; i++) { byte[] partialResult = l1hash[i].digest(); System.arraycopy(partialResult, 0, result, 4 * i, 4); } reset(); return result; } public void reset() { for (int i = 0; i < streams; i++) { l1hash[i].reset(); } } public boolean selfTest() { return true; } // helper methods ---------------------------------------------------------- // Inner classes // ========================================================================= /** * First hash stage of the UHash32 algorithm. */ class L1Hash32 implements Cloneable { // Constants and variables // ---------------------------------------------------------------------- private int[] key; // key material as an array of 32-bit ints private byte[] buffer; // work buffer L1_KEY_LEN long private int count; // meaningful bytes in buffer private ByteArrayOutputStream Y; // private byte[] y; private long totalCount; private L2Hash32 l2hash; private L3Hash32 l3hash; // Constructor(s) // ---------------------------------------------------------------------- /** Trivial 0-arguments constructor. */ L1Hash32() { super(); key = new int[UMac32.L1_KEY_LEN / 4]; buffer = new byte[UMac32.L1_KEY_LEN]; count = 0; Y = new ByteArrayOutputStream(); totalCount = 0L; } /** * <p>Private constructor for cloning purposes.</p> * * @param that the instance to clone. */ private L1Hash32(L1Hash32 that) { this(); System.arraycopy(that.key, 0, this.key, 0, that.key.length); System.arraycopy(that.buffer, 0, this.buffer, 0, that.count); this.count = that.count; byte[] otherY = that.Y.toByteArray(); this.Y.write(otherY, 0, otherY.length); this.totalCount = that.totalCount; if (that.l2hash != null) { this.l2hash = (L2Hash32) that.l2hash.clone(); } if (that.l3hash != null) { this.l3hash = (L3Hash32) that.l3hash.clone(); } } // Class methods // ---------------------------------------------------------------------- // Instance methods // ---------------------------------------------------------------------- // java.lang.Cloneable interface implementation ------------------------- public Object clone() { return new L1Hash32(this); } // other instance methods ----------------------------------------------- public void init(byte[] k1, byte[] k2, byte[] k31, byte[] k32) { for (int i = 0, j = 0; i < (UMac32.L1_KEY_LEN / 4); i++) { key[i] = k1[j++] << 24 | (k1[j++] & 0xFF) << 16 | (k1[j++] & 0xFF) << 8 | (k1[j++] & 0xFF); } l2hash = new L2Hash32(k2); l3hash = new L3Hash32(k31, k32); } public void update(byte b) { // Break M into L1_KEY_LEN byte chunks (final chunk may be shorter) // Let M_1, M_2, ..., M_t be strings so that M = M_1 || M_2 || .. || // M_t, and length(M_i) = L1_KEY_LEN for all 0 < i < t. // For each chunk, except the last: endian-adjust, NH hash // and add bit-length. Use results to build Y. buffer[count] = b; count++; totalCount++; if (count >= UMac32.L1_KEY_LEN) { byte[] y = nh32(UMac32.L1_KEY_LEN); Y.write(y, 0, 8); count = 0; // For each iteration, extract key and three-layer hash. // If length(M) <= L1_KEY_LEN, then skip L2-HASH. if (Y.size() == 16) { // we already hashed twice L1_KEY_LEN byte[] A = Y.toByteArray(); Y.reset(); l2hash.update(A, 0, 16); } } } public byte[] digest() { // For the last chunk: pad to 32-byte boundary, endian-adjust, // NH hash and add bit-length. Concatenate the result to Y. if (count != 0) { if (count % 32 != 0) { int limit = 32 * ((count + 31) / 32); System.arraycopy(ALL_ZEROES, 0, buffer, count, limit - count); count += limit - count; } byte[] y = nh32(count); Y.write(y, 0, 8); } byte[] A = Y.toByteArray(); Y.reset(); byte[] B; if (totalCount <= UMac32.L1_KEY_LEN) { // we might have 'update'd the bytes already. check if (A.length == 0) { // we did B = l2hash.digest(); } else { // did not B = new byte[16]; System.arraycopy(A, 0, B, 8, 8); } } else { if (A.length != 0) { l2hash.update(A, 0, A.length); } B = l2hash.digest(); } byte[] result = l3hash.digest(B); reset(); return result; } public void reset() { count = 0; Y.reset(); totalCount = 0L; if (l2hash != null) { l2hash.reset(); } } // helper methods ------------------------------------------------------- /** * 5.1 NH-32: NH hashing with a 32-bit word size. * * @param len count of bytes, divisible by 32, in buffer to process * @return Y, string of length 8 bytes. */ private byte[] nh32(int len) { // Break M and K into 4-byte chunks int t = len / 4; // Let M_1, M_2, ..., M_t be 4-byte strings // so that M = M_1 || M_2 || .. || M_t. // Let K_1, K_2, ..., K_t be 4-byte strings // so that K_1 || K_2 || .. || K_t is a prefix of K. int[] m = new int[t]; int i; int j = 0; for (i = 0, j = 0; i < t; i++) { m[i] = buffer[j++] << 24 | (buffer[j++] & 0xFF) << 16 | (buffer[j++] & 0xFF) << 8 | (buffer[j++] & 0xFF); } // Perform NH hash on the chunks, pairing words for multiplication // which are 4 apart to accommodate vector-parallelism. long result = len * 8L; for (i = 0; i < t; i += 8) { result += ((m[i + 0] + key[i + 0]) & 0xFFFFFFFFL) * ((m[i + 4] + key[i + 4]) & 0xFFFFFFFFL); result += ((m[i + 1] + key[i + 1]) & 0xFFFFFFFFL) * ((m[i + 5] + key[i + 5]) & 0xFFFFFFFFL); result += ((m[i + 2] + key[i + 2]) & 0xFFFFFFFFL) * ((m[i + 6] + key[i + 6]) & 0xFFFFFFFFL); result += ((m[i + 3] + key[i + 3]) & 0xFFFFFFFFL) * ((m[i + 7] + key[i + 7]) & 0xFFFFFFFFL); } return new byte[] { (byte) (result >>> 56), (byte) (result >>> 48), (byte) (result >>> 40), (byte) (result >>> 32), (byte) (result >>> 24), (byte) (result >>> 16), (byte) (result >>> 8), (byte) result }; } } // ========================================================================= /** * <p>Second hash stage of the UHash32 algorithm.</p> * * 5.4 L2-HASH-32: Second-layer hash.<p> * <ul> * <li>Input:<br> * K string of length 24 bytes.<br> * M string of length less than 2^64 bytes.</li> * <li>Returns:<br> * Y, string of length 16 bytes.</li> * </ul> */ class L2Hash32 implements Cloneable { // Constants and variables // ---------------------------------------------------------------------- private BigInteger k64, k128; private BigInteger y; private boolean highBound; private long bytesSoFar; private ByteArrayOutputStream buffer; // Constructor(s) // ---------------------------------------------------------------------- L2Hash32(byte[] K) { super();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -