public TlshHash GetHash(bool force) { if (!IsValid(force)) { throw new InvalidOperationException("TLSH not valid. Either not enough data or data has too little variance"); } uint q1, q2, q3; uint[] quartiles = FindQuartiles(); q1 = quartiles[0]; q2 = quartiles[1]; q3 = quartiles[2]; var tmp_code = new int[codeSize]; for (int i = 0; i < codeSize; i++) { int h = 0; for (int j = 0; j < 4; j++) { var k = accumulatorBuckets[4 * i + j]; if (q3 < k) { h += 3 << (j * 2); } else if (q2 < k) { h += 2 << (j * 2); } else if (q1 < k) { h += 1 << (j * 2); } } tmp_code[i] = h; } int lvalue = TlshUtilities.LengthCapture(dataLength); int q1ratio = (int)((q1 * 100.0f) / q3) & 0xF; int q2ratio = (int)((q2 * 100.0f) / q3) & 0xF; if (checksumLength == 1) { return(new TlshHash(new int[] { checksum }, lvalue, q1ratio, q2ratio, tmp_code)); } else { var checksumArrayCopy = new int[checksumArray.Length]; Array.Copy(checksumArray, checksumArrayCopy, checksumArray.Length); return(new TlshHash(checksumArrayCopy, lvalue, q1ratio, q2ratio, tmp_code)); } }
public void LoadFromString(string input) { var buffer = new byte[1024]; using (var s = TlshUtilities.GenerateStreamFromString(input)) { var bytesRead = s.Read(buffer, 0, buffer.Length); while (bytesRead > 0) { Update(buffer, 0, bytesRead); bytesRead = s.Read(buffer, 0, buffer.Length); } } }
public async Task LoadFromStringAsync(string input) { var buffer = new byte[1024]; using (var s = TlshUtilities.GenerateStreamFromString(input)) { var bytesRead = await s.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); while (bytesRead > 0) { Update(buffer, 0, bytesRead); bytesRead = await s.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); } } }
private readonly int[] codes; // 32/64 bytes public static TlshHash FromTlshStr(string tlshStr) { int[] checksum = null; int[] tmp_code = null; foreach (BucketSize bucketSize in Enum.GetValues(typeof(BucketSize))) { foreach (ChecksumSize checksumOption in Enum.GetValues(typeof(ChecksumSize))) { if (tlshStr.Length == HashStringLength(bucketSize, checksumOption)) { checksum = new int[(int)checksumOption]; tmp_code = new int[(int)bucketSize / 4]; } } } if (checksum == null) { throw new ArgumentException("Invalid hash string, length does not match any known encoding"); } var offset = 0; for (int k = 0; k < checksum.Length; k++) { checksum[k] = TlshUtilities.FromHexSwapped(tlshStr, offset); offset += 2; } var Lvalue = TlshUtilities.FromHexSwapped(tlshStr, offset); offset += 2; var qRatios = TlshUtilities.FromHex(tlshStr, offset); offset += 2; for (int i = 0; i < tmp_code.Length; i++) { // un-reverse the code during encoding tmp_code[tmp_code.Length - i - 1] = TlshUtilities.FromHex(tlshStr, offset); offset += 2; } return(new TlshHash(checksum, Lvalue, qRatios >> 4, qRatios & 0xF, tmp_code)); }
public string GetEncoded() { // The C++ code reverses the order of some of the fields before // converting to hex, so copy that behaviour. var sb = new StringBuilder(HashStringLength()); for (int k = 0; k < checksum.Length; k++) { TlshUtilities.ToHexSwapped(checksum[k], sb); } TlshUtilities.ToHexSwapped(Lvalue, sb); TlshUtilities.ToHex(Q1ratio << 4 | Q2ratio, sb); for (int i = 0; i < codes.Length; i++) { // reverse the code during encoding TlshUtilities.ToHex(codes[codes.Length - 1 - i], sb); } return(sb.ToString()); }
public void Update(byte[] data, int offset, int byteArrDataLength) { const int RNG_SIZE = CSlidingWindowSize; // Indexes into the sliding window. They cycle like // 0 4 3 2 1 // 1 0 4 3 2 // 2 1 0 4 3 // 3 2 1 0 4 // 4 3 2 1 0 // 0 4 3 2 1 // and so on int j = dataLength % RNG_SIZE; int j_1 = (j - 1 + RNG_SIZE) % RNG_SIZE; int j_2 = (j - 2 + RNG_SIZE) % RNG_SIZE; int j_3 = (j - 3 + RNG_SIZE) % RNG_SIZE; int j_4 = (j - 4 + RNG_SIZE) % RNG_SIZE; int fedLength = dataLength; for (int i = offset; i < offset + byteArrDataLength; i++, fedLength++) { slideWindow[j] = data[i] & 0xFF; if (fedLength >= 4) { // only calculate when input >= 5 bytes checksum = TlshUtilities.PearsonHash(0, slideWindow[j], slideWindow[j_1], checksum); if (checksumLength > 1) { checksumArray[0] = checksum; for (int k = 1; k < checksumLength; k++) { // use calculated 1 byte checksums to expand the total checksum to 3 bytes checksumArray[k] = TlshUtilities.PearsonHash(checksumArray[k - 1], slideWindow[j], slideWindow[j_1], checksumArray[k]); } } int r; r = TlshUtilities.PearsonHash(2, slideWindow[j], slideWindow[j_1], slideWindow[j_2]); accumulatorBuckets[r]++; r = TlshUtilities.PearsonHash(3, slideWindow[j], slideWindow[j_1], slideWindow[j_3]); accumulatorBuckets[r]++; r = TlshUtilities.PearsonHash(5, slideWindow[j], slideWindow[j_2], slideWindow[j_3]); accumulatorBuckets[r]++; r = TlshUtilities.PearsonHash(7, slideWindow[j], slideWindow[j_2], slideWindow[j_4]); accumulatorBuckets[r]++; r = TlshUtilities.PearsonHash(11, slideWindow[j], slideWindow[j_1], slideWindow[j_4]); accumulatorBuckets[r]++; r = TlshUtilities.PearsonHash(13, slideWindow[j], slideWindow[j_3], slideWindow[j_4]); accumulatorBuckets[r]++; } // rotate the sliding window indexes int j_tmp = j_4; j_4 = j_3; j_3 = j_2; j_2 = j_1; j_1 = j; j = j_tmp; } dataLength += byteArrDataLength; }
public int TotalDiff(TlshHash otherHash, bool lengthDiff) { if (checksum.Length != otherHash.checksum.Length || codes.Length != otherHash.codes.Length) { throw new ArgumentException("Given TLSH structure was created with different options from this hash and cannot be compared"); } var diff = 0; if (lengthDiff) { var ldiff = TlshUtilities.ModDiff(Lvalue, otherHash.Lvalue, CRangeLValue); if (ldiff == 0) { diff = 0; } else if (ldiff == 1) { diff = 1; } else { diff += ldiff * 12; } } var q1diff = TlshUtilities.ModDiff(Q1ratio, otherHash.Q1ratio, CRangeQRatio); if (q1diff <= 1) { diff += q1diff; } else { diff += (q1diff - 1) * 12; } var q2diff = TlshUtilities.ModDiff(Q2ratio, otherHash.Q2ratio, CRangeQRatio); if (q2diff <= 1) { diff += q2diff; } else { diff += (q2diff - 1) * 12; } for (int k = 0; k < checksum.Length; k++) { if (checksum[k] != otherHash.checksum[k]) { diff++; break; } } diff += TlshUtilities.HashDistance(codes, otherHash.codes); return(diff); }