/// <summary> /// Initializes the state of Key Pair assuming the given Passphrase includes a higher then 100-bit /// entropy score using ZXCVBN analysis. Returns false if the Passphrase does not pass this test, and the /// object is not initialized as a result. Returns true with the Key Pair is ready for use. /// </summary> /// <param name="EMail"></param> /// <param name="Passphrase"></param> /// <returns>true if OK/Initialized, false if BAD PASSPHRASE</returns> public bool Initialize(string EMail, string Passphrase) { if (string.IsNullOrWhiteSpace(EMail)) { throw new ArgumentNullException("EMail"); } if (string.IsNullOrWhiteSpace(Passphrase)) { throw new ArgumentNullException("Passphrase"); } if ((int)ScorePotentialPassphrase(Passphrase).Entropy < 100) { return(false); } byte[] mangledPWD = Blake2S.ComputeHash(new UTF8Encoding().GetBytes(Passphrase.Trim())); _Secret = SCrypt.ComputeDerivedKey(mangledPWD, new UTF8Encoding().GetBytes(EMail.Trim()), 131072, 8, 1, 1, 32); _SecretChecksum = ComputeChecksum(_Secret); _PublicID = GeneratePublicIDFromSecret(_Secret, out _PublicChecksum); //PROTECT MEMORY AFTER LAST USE OF _Secret ProtectedMemory.Protect(_Secret, MemoryProtectionScope.SameProcess); _Public = GetBytesFromPublicKey(_PublicID); return(true); }
protected BLAKE2S(int bits) : base(GetHashType(bits), GetName(bits), bits / 8) { _factory = () => { var algo = new Blake2S(bits); algo.Initialize(); return(algo); }; }
/// <summary> /// Encode a publicKey into miniLock format. /// </summary> /// <param name="publicKey">A 32 byte publicKey.</param> /// <exception cref="Sodium.Exceptions.KeyOutOfRangeException"></exception> /// <returns>A Base58 encoded publicKey.</returns> public static string EncodeMiniLockPublicKey(byte[] publicKey) { if (publicKey == null || publicKey.Length != PublicKeyBytes) { throw new KeyOutOfRangeException("publicKey", (publicKey == null) ? 0 : publicKey.Length, string.Format("key must be {0} bytes in length.", PublicKeyBytes)); } var final = ArrayHelper.ConcatArrays(publicKey, Blake2S.Hash(publicKey, (byte[])null, 1)); return(Base58CheckEncoding.EncodePlain(final)); }
internal static byte ComputeChecksum(byte[] key) { if (key == null || (key.Length != 32 && key.Length != 33)) { throw new ArgumentOutOfRangeException("key must be 32 or 33 bytes"); } return(Blake2S.ComputeHash( key, 0, 32, new Blake2sConfig() { OutputSizeInBytes = 1 })[0]); }
private Blake2S[] DeepCloneBlake2SInstances(Blake2S[] leafHashes) { if (leafHashes == null) { return(null); } var result = new Blake2S[leafHashes.Length]; for (var idx = 0; idx < _leafHashes.Length; idx++) { result[idx] = _leafHashes[idx].CloneInternal(); } return(result); }
internal Blake2SP(int hashSize, byte[] key) : base(hashSize, BlockSizeInBytes) { if (key == null) { throw new ArgumentNullException(nameof(key)); } _key = ArrayUtils.Clone(key); _leafHashes = new Blake2S[ParallelismDegree]; _buffer = new byte[ParallelismDegree * BlockSizeInBytes]; _rootHash = Blake2SPCreateRoot(); for (var idx = 0; idx < ParallelismDegree; idx++) { _leafHashes[idx] = Blake2SPCreateLeaf((ulong)idx); } }
/// <summary> /// Decode a miniLock ID into a byte array. /// </summary> /// <param name="encodedPublicKey">The miniLock ID.</param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="CorruptIdentityException"></exception> /// <returns>A 32 byte array.</returns> public static byte[] DecodeMiniLockPublicKey(string encodedPublicKey) { if (encodedPublicKey == null) { throw new ArgumentNullException("encodedPublicKey", "encodedPublicKey cannot be null"); } var raw = Base58CheckEncoding.DecodePlain(encodedPublicKey); var publicKey = ArrayHelper.SubArray(raw, 0, 32); var checksum = ArrayHelper.SubArray(raw, 32); // validate the checksum if (!checksum.SequenceEqual(Blake2S.Hash(publicKey, (byte[])null, 1))) { throw new CorruptIdentityException("the given identity seems to be an invalid miniLock ID"); } return(publicKey); }
public void Test() { var vectors = new List <TestVector> { new TestVector { Id = 1, InputHex = "", KeyHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", ResultHex = "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49" }, new TestVector { Id = 2, InputHex = "00", KeyHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", ResultHex = "40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1" }, new TestVector { Id = 3, InputHex = "0001", KeyHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", ResultHex = "6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803" } }; foreach (var vector in vectors) { var result = TestHelper.StringToByteArray(vector.ResultHex); var hash = Blake2S.Hash(TestHelper.StringToByteArray(vector.InputHex), TestHelper.StringToByteArray(vector.KeyHex), result.Length); CollectionAssert.AreEqual(result, hash); Console.WriteLine("Test Vector " + vector.Id + ": passed"); } }
/// <summary> /// Generate a MiniLock Keypair from an email and a password. /// </summary> /// <param name="email">A valid (format) email address.</param> /// <param name="password">A password with a minimal entropy of 100.</param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="InvalidMailException"></exception> /// <exception cref="LowEntropyException"></exception> /// <returns>A libsodium compatible KeyPair.</returns> public static KeyPair GenerateMiniLockKeyPair(string email, string password) { const int minPasswordEntropy = 100; if (email == null) { throw new ArgumentNullException("email", "email cannot be null"); } // perform a simple email check if (!StringHelper.IsValidEmail(email)) { throw new InvalidMailException("the given email address seems to be invalid"); } if (password == null) { throw new ArgumentNullException("password", "password cannot be null"); } var passwordEntropy = Zxcvbn.Zxcvbn.MatchPassword(password).Entropy; // check the entropy if (passwordEntropy < 100) { throw new LowEntropyException( string.Format( "miniLock needs at least an entropy of {0}, the given password only has an entropy of {1}.", minPasswordEntropy, passwordEntropy)); } var passwordHash = Blake2S.Hash(Encoding.UTF8.GetBytes(password), (byte[])null, 32); var seed = SCrypt.ComputeDerivedKey(passwordHash, Encoding.UTF8.GetBytes(email), 131072, 8, 1, 1, 32); var keyPair = PublicKeyBox.GenerateKeyPair(seed); return(keyPair); }
/// <summary> /// Creates the hasher. /// </summary> private HashAlgorithm CreateHasher() { var hasher = SrpHash.CreateHasher(H); if (hasher == null) { HashAlgorithm blake2s() => Blake2S.Create().AsHashAlgorithm(); HashAlgorithm blake2b(int bits) => new Blake2BHasher(new Blake2BConfig { OutputSizeInBits = bits }) .AsHashAlgorithm(); switch (H.ToLowerInvariant()) { case "blake2s-256": return(blake2s()); case "blake2b-224": return(blake2b(224)); case "blake2b-256": return(blake2b(256)); case "blake2b-384": return(blake2b(384)); case "blake2b-512": return(blake2b(512)); } } return(hasher); }