// Computes Kc as described in rfc 8554 public BitString Algorithm4b(BitString sig, BitString msg, BitString pubType, BitString I, BitString q) { // 1. If the signature is not at least four bytes long, return INVALID. if (sig.BitLength < 32) { return(null); } // 2. Parse sigtype, C, and y from the signature as follows: // a. sigtype = strTou32(first 4 bytes of signature) var sigType = sig.MSBSubstring(0, 32); // b. If sigtype is not equal to pubtype, return INVALID. if (!pubType.Equals(sigType)) { return(null); } // c. Set n and p according to the pubtype and Table 1; if the signature is not exactly 4 + n * (p + 1) // bytes long, return INVALID. var p = LmotsModeMapping.GetPFromCode(sigType); var n = LmotsModeMapping.GetNFromCode(sigType); if (sig.BitLength != (4 + (n * (p + 1))) * 8) { return(null); } // d. C = next n bytes of signature var C = sig.MSBSubstring(32, n * 8); // e. y[0] = next n bytes of signature // y[1] = next n bytes of signature // ... // y[p - 1] = next n bytes of signature var y = sig.MSBSubstring((n * 8) + 32, p * n * 8); // 3. Compute the string Kc as described in rfc 8554 var Q = _sha256.HashMessage(I .ConcatenateBits(q) .ConcatenateBits(D_MESG) .ConcatenateBits(C) .ConcatenateBits(msg)).Digest; var cksmQ = CheckSum(Q); var QcksmQ = Q.ConcatenateBits(cksmQ); var z = LmsDllLoader.GenZ(_p, _n, _w, y.ToBytes(), QcksmQ.ToBytes(), I.ToBytes(), q.ToBytes()); var concatenated = I.ConcatenateBits(q).ConcatenateBits(D_PBLC); concatenated = concatenated.ConcatenateBits(new BitString(z)); var Kc = _sha256.HashMessage(concatenated).Digest; // 4. Return Kc. return(Kc); }
public HssVerificationResult VerifyHssSignature(BitString msg, BitString publicKey, BitString signature) { // 1. The signature S is parsed into its components as follows: // a. Nspk = strTou32(first four bytes of S) // if Nspk+1 is not equal to the number of levels L in pub return INVALID var Nspk = (int)signature.MSBSubstring(0, 32).ToPositiveBigInteger(); var lengthInPublic = (int)publicKey.MSBSubstring(0, 32).ToPositiveBigInteger(); if (Nspk + 1 != lengthInPublic) { return(new HssVerificationResult("Validation failed. L values do not match.")); } // b. for (i = 0; i<Nspk; i = i + 1) { // siglist[i] = next LMS signature parsed from S // publist[i] = next LMS public key parsed from S // } var siglist = new BitString[Nspk + 1]; var publist = new BitString[Nspk + 1]; var currIndex = 32; for (int i = 0; i < Nspk; i++) { // assume sig and pub have same LMS mode var otsCode = signature.MSBSubstring(currIndex + 32, 32); var n = LmotsModeMapping.GetNFromCode(otsCode); var p = LmotsModeMapping.GetPFromCode(otsCode); var sigtype = signature.MSBSubstring((8 + n * (p + 1)) * 8 + currIndex, 32); var m = LmsModeMapping.GetMFromCode(sigtype); var h = LmsModeMapping.GetHFromCode(sigtype); var siglen = (12 + n * (p + 1) + m * h) * 8; var publen = 192 + (m * 8); siglist[i] = signature.MSBSubstring(currIndex, siglen); currIndex += siglen; publist[i] = signature.MSBSubstring(currIndex, publen); currIndex += publen; } // c. siglist[Nspk] = next LMS signature parsed from S var otsCodeLast = signature.MSBSubstring(currIndex + 32, 32); var nLast = LmotsModeMapping.GetNFromCode(otsCodeLast); var pLast = LmotsModeMapping.GetPFromCode(otsCodeLast); var sigtypeLast = signature.MSBSubstring((8 + nLast * (pLast + 1)) * 8 + currIndex, 32); var mLast = LmsModeMapping.GetMFromCode(sigtypeLast); var hLast = LmsModeMapping.GetHFromCode(sigtypeLast); var siglenLast = (12 + nLast * (pLast + 1) + mLast * hLast) * 8; siglist[Nspk] = signature.MSBSubstring(currIndex, siglenLast); // 2. Verify each part of the signature var key = publicKey.MSBSubstring(32, publicKey.BitLength - 32); for (int i = 0; i < Nspk; i++) { var result = _lms[i].VerifyLmsSignature(publist[i], key, siglist[i]); if (!result.Success) { return(new HssVerificationResult("LMS Validation failed: " + result.ErrorMessage)); } key = publist[i]; } // 3. return lms_verify(message, key, siglist[Nspk]) var finalResult = _lms[Nspk].VerifyLmsSignature(msg, key, siglist[Nspk]); if (finalResult.Success) { return(new HssVerificationResult()); } else { return(new HssVerificationResult("Validation failed. Final check failed: " + finalResult.ErrorMessage)); } }
public LmsVerificationResult VerifyLmsSignature(BitString msg, BitString publicKey, BitString signature) { // 1. If the public key is not at least eight bytes long, return INVALID. if (publicKey.BitLength < 64) { return(new LmsVerificationResult("Validation failed. Public key wrong length.")); } // 2. Parse pubtype, I, and T[1] from the public key as follows: // a. pubtype = strTou32(first 4 bytes of public key) var pubType = publicKey.MSBSubstring(0, 32); // b. ots_typecode = strTou32(next 4 bytes of public key) var ots_typecode = publicKey.MSBSubstring(32, 32); // c. Set m according to pubtype, based on Table 2. var m = LmsModeMapping.GetMFromCode(pubType); // d. If the public key is not exactly 24 + m bytes long, return INVALID. if (publicKey.BitLength != (24 + m) * 8) { return(new LmsVerificationResult("Validation failed. Public key wrong length.")); } // e. I = next 16 bytes of the public key var I = publicKey.MSBSubstring(64, 128); // f. T[1] = next m bytes of the public key var root = publicKey.MSBSubstring(192, m * 8); // 3. Compute the LMS Public Key Candidate Tc from the signature, message, identifier, // pubtype, and ots_typecode, using Algorithm 6a. // Algorithm 6a: // 1. If the signature is not at least eight bytes long, return INVALID. if (signature.BitLength < 64) { return(new LmsVerificationResult("Validation failed. Signature wrong length.")); } // 2. Parse sigtype, q, lmots_signature, and path from the signature as follows: // a. q = strTou32(first 4 bytes of signature) var q = signature.MSBSubstring(0, 32); // b. otssigtype = strTou32(next 4 bytes of signature) var otssigtype = signature.MSBSubstring(32, 32); // c. If otssigtype is not the OTS typecode from the public key, return INVALID. if (!otssigtype.Equals(ots_typecode)) { return(new LmsVerificationResult("Validation failed. OTS Code incongruent.")); } // d. Set n, p according to otssigtype and Table 1; if the signature is not // at least 12 + n* (p + 1) bytes long, return INVALID. var n = LmotsModeMapping.GetNFromCode(otssigtype); var p = LmotsModeMapping.GetPFromCode(otssigtype); if (signature.BitLength < (12 + n * (p - 1)) * 8) { return(new LmsVerificationResult("Validation failed. Signature wrong length.")); } // e. lmots_signature = bytes 4 through 7 + n* (p + 1) of signature var lmots_signature = signature.MSBSubstring(32, (4 + n * (p + 1)) * 8); // f. sigtype = strTou32(bytes 8 + n* (p + 1)) through 11 + n* (p + 1) of signature) var sigtype = signature.MSBSubstring((8 + n * (p + 1)) * 8, 32); // g. If sigtype is not the LM typecode from the public key, return INVALID. if (!sigtype.Equals(pubType)) { return(new LmsVerificationResult("Verification failed. Type mismatch.")); } // h. Set m, h according to sigtype and Table 2. // m already set from above var h = LmsModeMapping.GetHFromCode(sigtype); // i. If q >= 2^h or the signature is not exactly 12 + n* (p + 1) + m* h bytes long, return INVALID. if (q.ToPositiveBigInteger() >= (1 << h) || signature.BitLength != (12 + n * (p + 1) + m * h) * 8) { return(new LmsVerificationResult("Verification failed. Signature wrong length.")); } // j. Set path as follows: // path[0] = next m bytes of signature // path[1] = next m bytes of signature // ... // path[h-1] = next m bytes of signature var path = new BitString[h]; for (int i = 0; i < h; i++) { path[i] = signature.MSBSubstring(((12 + n * (p + 1)) * 8) + (i * m * 8), m * 8); } // 3. Kc = candidate public key computed by applying Algorithm 4b to the signature lmots_signature, // the message, and the identifiers I, q var Kc = _lmots.Algorithm4b(lmots_signature, msg, otssigtype, I, q); if (Kc == null) { return(new LmsVerificationResult("Verification failed. Algorithm 4b failed.")); } // 4. Compute the candidate LMS root value Tc as described in rfc 8554 var node_num = (1 << h) + q.ToPositiveBigInteger(); var tmp = _sha256.HashMessage(I .ConcatenateBits(new BitString(node_num, 32)) .ConcatenateBits(D_LEAF) .ConcatenateBits(Kc)).Digest; for (int i = 0; node_num > 1; node_num /= 2) { if (node_num % 2 == 1) { tmp = _sha256.HashMessage(I .ConcatenateBits(new BitString(node_num / 2, 32)) .ConcatenateBits(D_INTR) .ConcatenateBits(path[i]) .ConcatenateBits(tmp)).Digest; } else { tmp = _sha256.HashMessage(I .ConcatenateBits(new BitString(node_num / 2, 32)) .ConcatenateBits(D_INTR) .ConcatenateBits(tmp) .ConcatenateBits(path[i])).Digest; } i++; } // 5. Return Tc var Tc = tmp; // END Algorithm 6a // 4. If Tc is equal to T[1], return VALID; otherwise, return INVALID. if (Tc.Equals(root)) { return(new LmsVerificationResult()); } else { return(new LmsVerificationResult("Verification failed. Signature invalid.")); } }