/// <summary> /// Determines which (if any) key is valid from a set of potential keys. /// </summary> /// <remarks> /// Where appropriate, computes confirmations in parallel. /// </remarks> /// <param name="keyConfirmation">Key confirmation configuration.</param> /// <param name="verifiedOutput">Known/verified output of the function if correct key is input.</param> /// <param name="potentialKeys">Set of potential keys used by the sender.</param> /// <exception cref="ArgumentNullException">Key confirmation configuration, verified output, or potential keys is null.</exception> /// <exception cref="ConfigurationInvalidException"> /// Some aspect of configuration invalid - detailed inside exception message. /// </exception> /// <returns>Valid key, or null if none are validated as being correct.</returns> public static SymmetricKey ConfirmKeyFromCanary(AuthenticationConfiguration keyConfirmation, byte[] verifiedOutput, IEnumerable <SymmetricKey> potentialKeys) { if (keyConfirmation == null) { throw new ArgumentNullException("keyConfirmation", "No configuration supplied."); } if (potentialKeys == null) { throw new ArgumentNullException("potentialKeys", "No potential keys supplied."); } Func <byte[], byte[]> validator = GetValidator(keyConfirmation, TagConstantBytes, keyConfirmation.SerialiseDto(), verifiedOutput.Length); SymmetricKey preKey = null; Parallel.ForEach(potentialKeys, (key, state) => { byte[] validationOut = validator(key.ConfirmationCanary); if (validationOut.SequenceEqual_ConstantTime(verifiedOutput)) { preKey = key; // Terminate all other validation function instances - we have found the key state.Stop(); } }); return(preKey); }
/// <summary> /// Generate a verified output of a function given the correct key, to be used as a key confirmation. /// Uses confirmation canary. /// </summary> /// <param name="configuration">Configuration of the verification function.</param> /// <param name="senderKeypair">Sender keypair to generate a confirmation output verification for.</param> /// <param name="recipientKey">Recipient key to generate a confirmation output verification for.</param> /// <returns>Output of the verification function, given the correct key.</returns> /// <exception cref="ArgumentException">Key is null or zero-length.</exception> /// <seealso cref="SymmetricKey"/> /// <seealso cref="ECKeypair"/> /// <seealso cref="IPossessConfirmationCanary"/> public static byte[] GenerateVerifiedOutput(AuthenticationConfiguration configuration, ECKeypair senderKeypair, ECKey recipientKey) { Func <byte[], byte[]> validator = GetValidator(configuration, TagConstantBytes, configuration.SerialiseDto()); byte[] canary = XorCanaryBytes(senderKeypair.ConfirmationCanary, recipientKey.ConfirmationCanary); byte[] verifiedOutput = validator(canary); Debug.Print(DebugUtility.CreateReportString("ConfirmationUtility", "GenerateVerifiedOutput", "Verified output", verifiedOutput.ToHexString())); return(verifiedOutput); }
/// <summary> /// Generate a verified output of a function given the correct canary, to be used as a key confirmation. /// </summary> /// <param name="configuration">Configuration of the verification function.</param> /// <param name="canary">Confirmation canary to generate a confirmation output verification for.</param> /// <returns>Output of the verification function, given the correct canary.</returns> /// <exception cref="ArgumentException">Key is null or zero-length.</exception> /// <seealso cref="SymmetricKey"/> /// <seealso cref="ECKeypair"/> /// <seealso cref="IPossessConfirmationCanary"/> public static byte[] GenerateVerifiedOutput(AuthenticationConfiguration configuration, byte[] canary) { if (canary.IsNullOrZeroLength()) { throw new ArgumentException("Canary is null or zero-length.", "canary"); } Func <byte[], byte[]> validator = GetValidator(configuration, TagConstantBytes, configuration.SerialiseDto()); byte[] verifiedOutput = validator(canary); Debug.Print(DebugUtility.CreateReportString("ConfirmationUtility", "GenerateVerifiedOutput", "Verified output", verifiedOutput.ToHexString())); return(verifiedOutput); }
/// <summary> /// Determines which (if any) key is valid from a set of potential keys. /// </summary> /// <remarks> /// Where appropriate, computes confirmations in parallel. /// </remarks> /// <param name="keyConfirmation">Key confirmation configuration.</param> /// <param name="verifiedOutput">Known/verified output of the function if correct key is input.</param> /// <param name="potentialSenderKeys">Set of potential public keys used by the sender.</param> /// <param name="ephemeralKey"></param> /// <param name="potentialRecipientKeys">Keys used by the recipient that the sender may have used.</param> /// <param name="senderKey">Output of the public key associated with the private key used by the sender.</param> /// <param name="recipientKeypair">Output of the keypair that contains the public key used by the sender.</param> /// <exception cref="ArgumentNullException">Some input argument is null.</exception> /// <exception cref="ConfigurationInvalidException"> /// Some aspect of configuration invalid - detailed inside exception message. /// </exception> /// <returns>Valid key, or null if none are validated as being correct.</returns> public static void ConfirmKeyFromCanary(AuthenticationConfiguration keyConfirmation, byte[] verifiedOutput, IEnumerable <ECKey> potentialSenderKeys, ECKey ephemeralKey, IEnumerable <ECKeypair> potentialRecipientKeys, out ECKey senderKey, out ECKeypair recipientKeypair) { if (keyConfirmation == null) { throw new ArgumentNullException("keyConfirmation", "No configuration supplied."); } if (ephemeralKey == null) { throw new ArgumentNullException("ephemeralKey", "No ephemeral key supplied."); } if (potentialSenderKeys == null) { throw new ArgumentNullException("potentialSenderKeys", "No potential sender keys supplied."); } if (ephemeralKey == null) { throw new ArgumentNullException("ephemeralKey", "No ephemeral key supplied."); } if (potentialRecipientKeys == null) { throw new ArgumentNullException("potentialRecipientKeys", "No potential recipient keys supplied."); } // We can determine which, if any, of the provided keys are capable of decrypting the manifest var viableSenderKeys = potentialSenderKeys.AsQueryExpr().Where(key => key.CurveProviderName.Equals(ephemeralKey.CurveProviderName) && key.CurveName.Equals(ephemeralKey.CurveName)).Run().ToArray(); if (viableSenderKeys.Length == 0) { throw new ArgumentException( "No viable sender keys found - curve provider and/or curve name do not match ephemeral key.", "potentialSenderKeys"); } var viableRecipientKeypairs = potentialRecipientKeys.AsQueryExpr().Where(key => key.CurveProviderName.Equals(ephemeralKey.CurveProviderName) && key.CurveName.Equals(ephemeralKey.CurveName)).Run().ToArray(); if (viableRecipientKeypairs.Length == 0) { throw new ArgumentException( "No viable recipient keys found - curve provider and/or curve name do not match ephemeral key.", "potentialRecipientKeys"); } Func <byte[], byte[]> validator = GetValidator(keyConfirmation, TagConstantBytes, keyConfirmation.SerialiseDto(), verifiedOutput.Length); // Temporary variables to store output in (can't access 'out' parameters inside anonymous method body) ECKey oSK = null; ECKeypair oRKP = null; // See which mode (by-sender / by-recipient) is better to run in parallel if (viableRecipientKeypairs.Length > viableSenderKeys.Length) { Parallel.ForEach(viableRecipientKeypairs, (rKeypair, state) => { foreach (ECKey sKey in viableSenderKeys) { byte[] canary = XorCanaryBytes(sKey.ConfirmationCanary, rKeypair.ConfirmationCanary); byte[] validationOut = validator(canary); if (validationOut.SequenceEqual_ConstantTime(verifiedOutput)) { oSK = sKey; oRKP = rKeypair; state.Stop(); } } }); } else { Parallel.ForEach(viableSenderKeys, (sKey, state) => { foreach (var rKeypair in viableRecipientKeypairs) { byte[] canary = XorCanaryBytes(sKey.ConfirmationCanary, rKeypair.ConfirmationCanary); byte[] validationOut = validator(canary); if (validationOut.SequenceEqual_ConstantTime(verifiedOutput)) { oSK = sKey; oRKP = rKeypair; state.Stop(); } } }); } // Assign the outputs to the 'out' parameters senderKey = oSK; recipientKeypair = oRKP; }