public void DeriveKeyWithString() { byte[] key = HexConvertor.GetBytes("1f5942ea0ab514227e339d14743b1df7707a868483725d6166d850d57cd33420"); byte[] resultOriginal = new byte[124]; SP800_108.DeriveKey("HMACSHA256", key, derivedOutput: resultOriginal); }
public void CompareOriginalSha256(string hexKey, string hexLabel, string hexContent, int iterations) { byte[] key = HexConvertor.GetBytes(hexKey); byte[] label = HexConvertor.GetBytes(hexLabel); byte[] content = HexConvertor.GetBytes(hexContent); Func <HMAC> hmacfactory = () => new HMACSHA256(); byte[] resultOriginal = new byte[124]; byte[] resultCustom = new byte[124]; SecurityDriven.Inferno.Kdf.SP800_108_Ctr.DeriveKey(hmacfactory, key, label.Length == 0 ? null : label, content.Length == 0 ? null : content, resultOriginal, (uint)iterations); SP800_108.DeriveKey(hmacfactory, key, label.Length == 0 ? Span <byte> .Empty : label, content.Length == 0 ? Span <byte> .Empty : content, resultCustom, (uint)iterations); Assert.AreEqual(HexConvertor.GetString(resultOriginal), HexConvertor.GetString(resultCustom)); }
/// <summary> /// Unprotect some data with the specified params. /// </summary> /// <param name="protectedData"></param> /// <param name="validationKey"></param> /// <param name="decryptionKey"></param> /// <param name="decryptionAlgorithmName"></param> /// <param name="validationAlgorithmName"></param> /// <param name="primaryPurpose"></param> /// <param name="specificPurposes"></param> /// <returns></returns> public static byte[] Unprotect(byte[] protectedData, string validationKey, string decryptionKey, string decryptionAlgorithmName, string validationAlgorithmName, string primaryPurpose, params string[] specificPurposes) { // The entire operation is wrapped in a 'checked' block because any overflows should be treated as failures. checked { using (SymmetricAlgorithm decryptionAlgorithm = CryptoConfig.CreateFromName(decryptionAlgorithmName) as SymmetricAlgorithm) { decryptionAlgorithm.Key = SP800_108.DeriveKey(HexToBinary(decryptionKey), primaryPurpose, specificPurposes); // These KeyedHashAlgorithm instances are single-use; we wrap it in a 'using' block. using (HashAlgorithm validationAlgorithm = CryptoConfig.CreateFromName(validationAlgorithmName) as HashAlgorithm) { if (validationAlgorithm is KeyedHashAlgorithm keydValidationAlgorithm) { keydValidationAlgorithm.Key = SP800_108.DeriveKey(HexToBinary(validationKey), primaryPurpose, specificPurposes); } int ivByteCount = decryptionAlgorithm.BlockSize / 8; int signatureByteCount = validationAlgorithm.HashSize / 8; int encryptedPayloadByteCount = protectedData.Length - ivByteCount - signatureByteCount; if (encryptedPayloadByteCount <= 0) { return(null); } byte[] computedSignature = validationAlgorithm.ComputeHash(protectedData, 0, ivByteCount + encryptedPayloadByteCount); if (!BuffersAreEqual( buffer1: protectedData, buffer1Offset: ivByteCount + encryptedPayloadByteCount, buffer1Count: signatureByteCount, buffer2: computedSignature, buffer2Offset: 0, buffer2Count: computedSignature.Length)) { return(null); } byte[] iv = new byte[ivByteCount]; Buffer.BlockCopy(protectedData, 0, iv, 0, iv.Length); decryptionAlgorithm.IV = iv; using (MemoryStream memStream = new MemoryStream()) { using (ICryptoTransform decryptor = decryptionAlgorithm.CreateDecryptor()) { using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Write)) { cryptoStream.Write(protectedData, ivByteCount, encryptedPayloadByteCount); cryptoStream.FlushFinalBlock(); byte[] clearData = memStream.ToArray(); return(clearData); } } } } } } }
public static byte[] Unprotect(byte[] protectedData, string validationKey, string decryptionKey, string decryptionAlgorithmName, string validationAlgorithmName, string primaryPurpose, params string[] specificPurposes) { using (SymmetricAlgorithm symmetricAlgorithm = CryptoConfig.CreateFromName(decryptionAlgorithmName) as SymmetricAlgorithm) { symmetricAlgorithm.Key = SP800_108.DeriveKey(HexToBinary(decryptionKey), primaryPurpose, specificPurposes); using (KeyedHashAlgorithm keyedHashAlgorithm = CryptoConfig.CreateFromName(validationAlgorithmName) as KeyedHashAlgorithm) { keyedHashAlgorithm.Key = SP800_108.DeriveKey(HexToBinary(validationKey), primaryPurpose, specificPurposes); int blockCount = symmetricAlgorithm.BlockSize / 8; int hashCount = keyedHashAlgorithm.HashSize / 8; checked { int dataCount = protectedData.Length - blockCount - hashCount; if (dataCount <= 0) { return(null); } byte[] hash = keyedHashAlgorithm.ComputeHash(protectedData, 0, blockCount + dataCount); if (BuffersAreEqual(protectedData, blockCount + dataCount, hashCount, hash, 0, hash.Length)) { byte[] iv = new byte[blockCount]; Buffer.BlockCopy(protectedData, 0, iv, 0, iv.Length); symmetricAlgorithm.IV = iv; using (MemoryStream memoryStream = new MemoryStream()) { using (ICryptoTransform transform = symmetricAlgorithm.CreateDecryptor()) { using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write)) { cryptoStream.Write(protectedData, blockCount, dataCount); cryptoStream.FlushFinalBlock(); return(memoryStream.ToArray()); } } } } return(null); } } } }
public AspNetDecryptor(Purpose purpose, CryptographicKey decryptionKey, CryptographicKey validationKey, bool isGzipped) { this.decryptionKey = SP800_108.DeriveKey(decryptionKey, purpose); this.validationKey = SP800_108.DeriveKey(validationKey, purpose); this.isGzipped = isGzipped; }
/// <summary> /// Protect some data with the specified params. /// </summary> /// <param name="clearData"></param> /// <param name="validationKey"></param> /// <param name="decryptionKey"></param> /// <param name="decryptionAlgorithmName"></param> /// <param name="validationAlgorithmName"></param> /// <param name="primaryPurpose"></param> /// <param name="specificPurposes"></param> /// <returns></returns> public static byte[] Protect(byte[] clearData, string validationKey, string decryptionKey, string decryptionAlgorithmName, string validationAlgorithmName, string primaryPurpose, params string[] specificPurposes) { // The entire operation is wrapped in a 'checked' block because any overflows should be treated as failures. checked { // These SymmetricAlgorithm instances are single-use; we wrap it in a 'using' block. using (SymmetricAlgorithm encryptionAlgorithm = CryptoConfig.CreateFromName(decryptionAlgorithmName) as SymmetricAlgorithm) { // Initialize the algorithm with the specified key and an appropriate IV encryptionAlgorithm.Key = SP800_108.DeriveKey(HexToBinary(decryptionKey), primaryPurpose, specificPurposes); // If the caller didn't ask for a predictable IV, just let the algorithm itself choose one. encryptionAlgorithm.GenerateIV(); // IV retrieval byte[] iv = encryptionAlgorithm.IV; using (MemoryStream memStream = new MemoryStream()) { memStream.Write(iv, 0, iv.Length); // At this point: // memStream := IV // Write the encrypted payload to the memory stream. using (ICryptoTransform encryptor = encryptionAlgorithm.CreateEncryptor()) { using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write)) { cryptoStream.Write(clearData, 0, clearData.Length); cryptoStream.FlushFinalBlock(); // At this point: // memStream := IV || Enc(Kenc, IV, clearData) // These KeyedHashAlgorithm instances are single-use; we wrap it in a 'using' block. using (HashAlgorithm signingAlgorithm = CryptoConfig.CreateFromName(validationAlgorithmName) as HashAlgorithm) { // Initialize the algorithm with the specified key if it's KeyedHashAlgorithm if (signingAlgorithm is KeyedHashAlgorithm keydSigningAlgorithm) { keydSigningAlgorithm.Key = SP800_108.DeriveKey(HexToBinary(validationKey), primaryPurpose, specificPurposes); } // Compute the signature byte[] signature = signingAlgorithm.ComputeHash(memStream.GetBuffer(), 0, (int)memStream.Length); // At this point: // memStream := IV || Enc(Kenc, IV, clearData) // signature := Sign(Kval, IV || Enc(Kenc, IV, clearData)) // Append the signature to the encrypted payload memStream.Write(signature, 0, signature.Length); // At this point: // memStream := IV || Enc(Kenc, IV, clearData) || Sign(Kval, IV || Enc(Kenc, IV, clearData)) // Algorithm complete byte[] protectedData = memStream.ToArray(); return(protectedData); } } } } } } }
static void Main(string[] args) { string key = null, context = null, label = null; string[] labels = new string[0]; bool showhelp = false; var p = new OptionSet { { "k|key=", "the validation key (in hex)", v => key = v }, { "c|context=", "the context", v => context = v }, { "l|labels=", "the labels, separated by commas", v => label = v }, { "h|help", "show this message and exit", v => showhelp = v != null }, { "?", "show this message and exit", v => showhelp = v != null } }; try { p.Parse(args).FirstOrDefault(); } catch (OptionException ex) { Console.Error.Write("ERROR: invalid argument, "); Console.Error.WriteLine(ex.Message); Console.Error.WriteLine(); showhelp = true; } if (!showhelp && key == null) { Console.Error.WriteLine("ERROR: the key is missing"); Console.Error.WriteLine(); showhelp = true; } if (label != null) { labels = label.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } if (!showhelp && context == null) { Console.Error.WriteLine("ERROR: the context is missing"); Console.Error.WriteLine(); showhelp = true; } if (showhelp) { ShowHelp(p); return; } Debug.Assert(context != null); Debug.Assert(key != null); if (key.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { key = key.Substring(2); } var purpose = new Purpose(context, labels); var keyBytes = CryptoUtil.HexToBinary(key); if (keyBytes == null) { Console.Error.WriteLine("ERROR: the key is invalid"); Console.Error.WriteLine(); return; } Console.WriteLine(Hexify.Hex.PrettyPrint(SP800_108.DeriveKey( new CryptographicKey(keyBytes), purpose).GetKeyMaterial())); }