public KeyProvider(int keysToMake = 5) { var symKeys = new List <SymmetricKey>(); var ecKeypairs = new List <ECKeypair>(); for (int i = 0; i < keysToMake; i++) { // Symmetric key var newSymKey = new byte[128.BitsToBytes()]; var newSymCanary = new byte[128.BitsToBytes()]; StratCom.EntropySupplier.NextBytes(newSymKey); StratCom.EntropySupplier.NextBytes(newSymCanary); symKeys.Add(new SymmetricKey { Key = newSymKey, ConfirmationCanary = newSymCanary, UsePermissions = SymmetricKeyUsePermission.Encryption | SymmetricKeyUsePermission.Authentication, ContextPermissions = KeyUseContextPermission.ManifestHeader | KeyUseContextPermission.PayloadItem }); // EC key int curveIndex = StratCom.EntropySupplier.Next(Athena.Cryptography.EllipticCurves.Count); string curveName = Athena.Cryptography.EllipticCurves.Keys.ElementAt(curveIndex); ECKeypair newEcKey = KeypairFactory.GenerateECKeypair(curveName); ecKeypairs.Add(newEcKey); } SymmetricKeys = symKeys; EcKeypairs = ecKeypairs; }
/// <summary> /// Create a key provider with keys based off an existing key provider, /// aimed at a sender-recipient relationship. /// </summary> /// <param name="other">Existing key provider to use as a basis for interoperability.</param> public KeyProvider(KeyProvider other) { SymmetricKeys = other.SymmetricKeys.Reverse().ToList(); EcKeypairs = other.EcKeypairs.Select( item => { ECKeypair newEcKeypair = KeypairFactory.GenerateECKeypair(item.CurveName); var newEcCanary = new byte[128.BitsToBytes()]; StratCom.EntropySupplier.NextBytes(newEcCanary); newEcKeypair.ConfirmationCanary = newEcCanary; return(newEcKeypair); }).ToList(); }
public void DJB_Ed25519_Blake2B512() { byte[] data = TEST; var digest = new Blake2BDigest(512); var m = new byte[digest.OutputSize]; digest.BlockUpdate(data, 0, data.Length); digest.DoFinal(m, 0); ECKeypair keypair = KeypairFactory.GenerateECKeypair(DjbCurve.Ed25519.ToString()); byte[] sig = Ed25519.Sign(m, keypair.EncodedPrivateKey); bool good = Ed25519.Verify(sig, m, keypair.EncodedPublicKey); Assert.IsTrue(good); }
/// <summary> /// Calculate the shared secret in participant U's (initiator) role. /// </summary> /// <param name="recipientPublicKey">Public key of the recipient.</param> /// <param name="senderPrivateKey">Private key of the sender.</param> /// <param name="ephemeralSenderPublicKey"> /// Ephemeral public key to send to the responder (V, receiver). Output to this /// parameter. /// </param> public static byte[] Initiate(ECKey recipientPublicKey, ECKey senderPrivateKey, out ECKey ephemeralSenderPublicKey) { if (recipientPublicKey.PublicComponent == false) { throw new ArgumentException("Recipient key is not public component.", "recipientPublicKey"); } if (senderPrivateKey.PublicComponent) { throw new ArgumentException("Sender key not private component.", "senderPrivateKey"); } ECKey Q_static_V = recipientPublicKey; ECKey d_static_U = senderPrivateKey; ECKeypair kp_ephemeral_U = KeypairFactory.GenerateECKeypair(senderPrivateKey.CurveName); ECKey Q_ephemeral_U = kp_ephemeral_U.ExportPublicKey(); ECKey d_ephemeral_U = kp_ephemeral_U.GetPrivateKey(); // Calculate shared ephemeral secret 'Ze' byte[] Ze = KeyAgreementFactory.CalculateEcdhcSecret(Q_static_V, d_ephemeral_U); // Calculate shared static secret 'Zs' byte[] Zs = KeyAgreementFactory.CalculateEcdhcSecret(Q_static_V, d_static_U); // Concatenate Ze and Zs byte strings to form shared secret, pre-KDF : Ze||Zs var Z = new byte[Ze.Length + Zs.Length]; Ze.DeepCopy_NoChecks(0, Z, 0, Ze.Length); Zs.DeepCopy_NoChecks(0, Z, Ze.Length, Zs.Length); ephemeralSenderPublicKey = Q_ephemeral_U; // Zero intermediate secrets Ze.SecureWipe(); Zs.SecureWipe(); return(Z); }
/// <summary> /// Create a new elliptic curve keypair. /// </summary> /// <param name="curveName">Name of the elliptic curve to use as the basis.</param> /// <returns>Elliptic curve keypair.</returns> public static ECKeypair GenerateECKeypair(string curveName, bool generateCanary = true) { ECKeypair keypair; if (curveName.Equals(DjbCurve.Curve25519.ToString())) { var privEntropy = new byte[Curve25519.PrivateKeySeedSizeInBytes]; StratCom.EntropySupplier.NextBytes(privEntropy); byte[] privateKey = Curve25519.CreatePrivateKey(privEntropy); byte[] publicKey = Curve25519.CreatePublicKey(privateKey); byte[] canary = null; if (generateCanary) { canary = new byte[128.BitsToBytes()]; StratCom.EntropySupplier.NextBytes(canary); } keypair = new ECKeypair { CurveProviderName = "DJB", CurveName = DjbCurve.Curve25519.ToString(), EncodedPublicKey = publicKey, EncodedPrivateKey = privateKey, UsePermissions = AsymmetricKeyUsePermission.KeyAgreements, ContextPermissions = KeyUseContextPermission.ManifestHeader, ConfirmationCanary = canary }; privEntropy.SecureWipe(); } else if (curveName.Equals(DjbCurve.Ed25519.ToString())) { var privEntropy = new byte[Ed25519.PrivateKeySeedSizeInBytes]; StratCom.EntropySupplier.NextBytes(privEntropy); byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; byte[] publicKey = new byte[Ed25519.PublicKeySizeInBytes]; Ed25519.KeyPairFromSeed(out publicKey, out privateKey, privEntropy); byte[] canary = null; if (generateCanary) { canary = new byte[128.BitsToBytes()]; StratCom.EntropySupplier.NextBytes(canary); } keypair = new ECKeypair { CurveProviderName = "DJB", CurveName = DjbCurve.Ed25519.ToString(), EncodedPublicKey = publicKey, EncodedPrivateKey = privateKey, UsePermissions = AsymmetricKeyUsePermission.KeyAgreements | AsymmetricKeyUsePermission.Signatures, ContextPermissions = KeyUseContextPermission.ManifestHeader, ConfirmationCanary = canary }; privEntropy.SecureWipe(); } else { ECPoint Q; BigInteger d; GenerateECKeypair(curveName, out Q, out d); byte[] canary = null; if (generateCanary) { canary = new byte[128.BitsToBytes()]; StratCom.EntropySupplier.NextBytes(canary); } keypair = new ECKeypair { CurveProviderName = EcInformationStore.GetProvider(curveName), CurveName = curveName, EncodedPublicKey = Q.GetEncoded(), EncodedPrivateKey = d.ToByteArray(), UsePermissions = AsymmetricKeyUsePermission.KeyAgreements | AsymmetricKeyUsePermission.Signatures, ContextPermissions = KeyUseContextPermission.ManifestHeader, ConfirmationCanary = canary }; } return(keypair); }
/// <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> /// 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; }