/// <summary> /// Default constructor for Symmetric key algorithm /// </summary> /// <param name="algorithm">Algorithm to use</param> /// <param name="keySizeInBits">Key size in bits, e.g. 256</param> /// <param name="settings">Settings for chosen algorithm</param> public SymmetricKeyAlgorithm(SymmetricEncryptionAlgorithm algorithm, int keySizeInBits, object settings) { this.algorithm = algorithm.ToString(); if (algorithm == SymmetricEncryptionAlgorithm.AES_CTR) { if (!Array.Exists(AES_CTR.allowedKeyLengths, allowed => allowed * 8 == keySizeInBits)) { throw new ArgumentException($"{keySizeInBits} is not valid AES-CTR key size!"); } this.settingsAES_CTR = (SettingsAES_CTR)settings; } else if (algorithm == SymmetricEncryptionAlgorithm.ChaCha20) { if (ChaCha20.allowedKeyLength * 8 != keySizeInBits) { throw new ArgumentException($"{keySizeInBits} is not valid ChaCha20 key size!"); } this.settingsChaCha20 = (SettingsChaCha20)settings; } else { throw new NotImplementedException($"{algorithm} constructor not implemented yet!"); } this.keySizeInBits = keySizeInBits; }
public void SetPassword(SymmetricEncryptionAlgorithm cryptoAlgo, int keySize, string password) { int keySizeBytes = keySize / 8; _kdf = PBKDF2.CreateHMACSHA256(password, keySizeBytes, PBKDF2_ITERATION_COUNT); byte[] key = _kdf.GetBytes(keySizeBytes); _containerKey = new SymmetricCryptoKey(cryptoAlgo, key); _hmac = new HMACSHA256(key); }
public SymmetricCryptoKey(SymmetricEncryptionAlgorithm cryptoAlgo, int keySize, PaddingMode padding = PaddingMode.ISO10126) { _symAlgo = SymmetricAlgorithm.Create(cryptoAlgo.ToString()); _symAlgo.KeySize = keySize; _symAlgo.Padding = padding; _symAlgo.Mode = CipherMode.CBC; _symAlgo.GenerateKey(); _symAlgo.GenerateIV(); _cryptoAlgo = cryptoAlgo; }
/// <summary> /// Encrypts the specified plaintext /// </summary> public string Encrypt(string plainText, byte[] key, byte[] iv, SymmetricEncryptionAlgorithm algorithm, PaddingMode?paddingMode = null) { var hash = Encrypt( Encoding.ASCII.GetBytes(plainText), key, iv, algorithm, paddingMode); return(Convert.ToBase64String(hash)); }
/// <summary> /// Decrypts the specified hash. /// </summary> public string Decrypt(string hash, byte[] key, byte[] iv, SymmetricEncryptionAlgorithm algorithm, PaddingMode?paddingMode = null) { var plainText = Decrypt( Convert.FromBase64String(hash), key, iv, algorithm, paddingMode); return(Encoding.ASCII.GetString(plainText)); }
/// <summary> /// Returns a new symmetric algorithm instance to be used during the /// encryption/decryption operations. The algorithm to create is chosen /// using the algorithm field. /// </summary> private SymmetricAlgorithm GetNewSymmetricAlgorithm(byte[] key, byte[] iv, SymmetricEncryptionAlgorithm algorithm, PaddingMode?paddingMode) { SymmetricAlgorithm symmetricAlgorithm; switch (algorithm) { case SymmetricEncryptionAlgorithm.Des: symmetricAlgorithm = new DESCryptoServiceProvider(); byte[] desKey = new byte[8]; byte[] desIV = new byte[8]; Array.Copy(key, 0, desKey, 0, 8); Array.Copy(iv, 0, desIV, 0, 8); symmetricAlgorithm.Key = desKey; symmetricAlgorithm.IV = desIV; break; case SymmetricEncryptionAlgorithm.TripleDes: symmetricAlgorithm = new TripleDESCryptoServiceProvider(); symmetricAlgorithm.Key = key; symmetricAlgorithm.IV = iv; break; case SymmetricEncryptionAlgorithm.Rijndael: symmetricAlgorithm = new RijndaelManaged(); symmetricAlgorithm.Key = key; symmetricAlgorithm.IV = iv; break; default: throw new ArgumentOutOfRangeException("algorithm"); } if (paddingMode.HasValue) { symmetricAlgorithm.Padding = paddingMode.Value; } return(symmetricAlgorithm); }
/// <summary> /// Encrypts the specified plaintext /// </summary> public byte[] Encrypt(byte[] plainText, byte[] key, byte[] iv, SymmetricEncryptionAlgorithm algorithm, PaddingMode?paddingMode = null) { using (SymmetricAlgorithm symmetricAlgorithm = this.GetNewSymmetricAlgorithm(key, iv, algorithm, paddingMode)) { using (MemoryStream ms = new MemoryStream()) { using (ICryptoTransform encryptor = symmetricAlgorithm.CreateEncryptor()) { using (CryptoStream cryptoStream = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { cryptoStream.Write(plainText, 0, plainText.Length); cryptoStream.FlushFinalBlock(); } } return(ms.ToArray()); } } }
public SymmetricCryptoKey(SymmetricEncryptionAlgorithm cryptoAlgo, byte[] key, byte[] IV = null, PaddingMode padding = PaddingMode.ISO10126) { _symAlgo = SymmetricAlgorithm.Create(cryptoAlgo.ToString()); _symAlgo.KeySize = key.Length * 8; _symAlgo.Padding = padding; _symAlgo.Mode = CipherMode.CBC; _symAlgo.Key = key; if (IV == null) { _symAlgo.GenerateIV(); } else { _symAlgo.IV = IV; } _cryptoAlgo = cryptoAlgo; }
public SymmetricCryptoKey(Stream s) { BinaryReader bR = new BinaryReader(s); if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "SK") { throw new CryptoException("Invalid SymmetricCryptoKey format."); } byte version = bR.ReadByte(); switch (version) //version { case 1: case 2: //algorithm _cryptoAlgo = (SymmetricEncryptionAlgorithm)bR.ReadByte(); _symAlgo = SymmetricAlgorithm.Create(_cryptoAlgo.ToString()); //key _symAlgo.Key = bR.ReadBytes(bR.ReadByte()); //IV _symAlgo.IV = bR.ReadBytes(bR.ReadByte()); //padding if (version == 1) { _symAlgo.Padding = PaddingMode.ISO10126; } else { _symAlgo.Padding = (PaddingMode)bR.ReadByte(); } _symAlgo.Mode = CipherMode.CBC; break; default: throw new CryptoException("SymmetricCryptoKey format version not supported."); } }
/// <summary> /// Decrypts the specified hash. /// </summary> public byte[] Decrypt(byte[] hash, byte[] key, byte[] iv, SymmetricEncryptionAlgorithm algorithm, PaddingMode?paddingMode = null) { using (SymmetricAlgorithm symmetricAlgorithm = this.GetNewSymmetricAlgorithm(key, iv, algorithm, paddingMode)) { using (ICryptoTransform decryptor = symmetricAlgorithm.CreateDecryptor()) { using (CryptoStream cryptoStream = new CryptoStream(new MemoryStream(hash), decryptor, CryptoStreamMode.Read)) { using (MemoryStream ms = new MemoryStream()) { byte[] buffer = new byte[BufferSize]; int readBytes; while ((readBytes = cryptoStream.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, buffer.Length); } return(ms.ToArray()); } } } } }
public CryptoContainer(SymmetricEncryptionAlgorithm cryptoAlgo, int keySize, string password) { SetPassword(cryptoAlgo, keySize, password); }
private void ReadFrom(Stream s, string password) { byte[] format = new byte[2]; s.Read(format, 0, 2); if (Encoding.ASCII.GetString(format) != "CC") { throw new InvalidCryptoContainerException("Invalid CryptoContainer format."); } switch (s.ReadByte()) //version { case 0: ReadPlainTextFrom(s); break; case 1: //depricated version { if (password == null) { throw new InvalidCryptoContainerException("Password required."); } //CryptoAlgo SymmetricEncryptionAlgorithm cryptoAlgo = (SymmetricEncryptionAlgorithm)s.ReadByte(); //KeySizeBytes int keySizeBytes = s.ReadByte(); byte[] IV = new byte[s.ReadByte()]; s.Read(IV, 0, IV.Length); byte[] key; switch (keySizeBytes) { case 16: key = HashAlgorithm.Create("MD5").ComputeHash(Encoding.UTF8.GetBytes(password)); break; case 32: key = HashAlgorithm.Create("SHA256").ComputeHash(Encoding.UTF8.GetBytes(password)); break; default: throw new CryptoException("CryptoContainer key size not supported."); } _containerKey = new SymmetricCryptoKey(cryptoAlgo, key, IV); ReadPlainTextFrom(_containerKey.GetCryptoStreamReader(s)); //auto upgrade to version 2 with PBKDF2-HMAC-SHA256 when calling WriteTo _kdf = PBKDF2.CreateHMACSHA256(password, keySizeBytes, PBKDF2_ITERATION_COUNT); key = _kdf.GetBytes(keySizeBytes); _containerKey = new SymmetricCryptoKey(cryptoAlgo, key, IV); _hmac = new HMACSHA256(key); } break; case 2: //using PBKDF2-HMAC-SHA256 { if (password == null) { throw new InvalidCryptoContainerException("Password required."); } //CryptoAlgo SymmetricEncryptionAlgorithm cryptoAlgo = (SymmetricEncryptionAlgorithm)s.ReadByte(); //KeySizeBytes int keySizeBytes = s.ReadByte(); byte[] IV = new byte[s.ReadByte()]; s.Read(IV, 0, IV.Length); byte[] salt = new byte[s.ReadByte()]; s.Read(salt, 0, salt.Length); byte[] HMAC = new byte[s.ReadByte()]; s.Read(HMAC, 0, HMAC.Length); _kdf = PBKDF2.CreateHMACSHA256(password, salt, PBKDF2_ITERATION_COUNT); byte[] key = _kdf.GetBytes(keySizeBytes); //authenticate data _hmac = new HMACSHA256(key); long startPosition = s.Position; byte[] computedHMAC = _hmac.ComputeHash(s); s.Position = startPosition; //verify hmac for (int i = 0; i < HMAC.Length; i++) { if (HMAC[i] != computedHMAC[i]) { throw new CryptoException("Invalid password or data tampered."); } } //decrypt data _containerKey = new SymmetricCryptoKey(cryptoAlgo, key, IV); ReadPlainTextFrom(_containerKey.GetCryptoStreamReader(s)); } break; case -1: throw new EndOfStreamException(); default: throw new InvalidCryptoContainerException("CryptoContainer format version not supported."); } }
/// <summary> /// Add contact to Common secret container /// </summary> /// <param name="password">Plaintext password</param> /// <param name="contact">Contact to add</param> /// <param name="keyIdentifier">Key identifier</param> /// <param name="algorithm">Symmetric Encryption Algorithm to use</param> /// <returns>Tuple that tells if add was success, and possible error</returns> public (bool success, string possibleError) AddContactSecret(string password, Contact contact, string keyIdentifier, SymmetricEncryptionAlgorithm algorithm = SymmetricEncryptionAlgorithm.AES_CTR) { (bool checkResult, string possibleError) = MandatoryChecks(contact, "Contact", keyIdentifier, password); if (!checkResult) { return(checkResult, possibleError); } SymmetricKeyAlgorithm ska = SymmetricKeyAlgorithm.GenerateNew(algorithm); byte[] derivedPassword = this.FindKeyDerivationFunctionEntryWithKeyIdentifier(keyIdentifier).GeneratePasswordBytes(password); this.contactSecrets.Add(new ContactSecret(contact, keyIdentifier, ska, derivedPassword)); return(success : true, possibleError : ""); }
/// <summary> /// Add file entry to Common secret container /// </summary> /// <param name="derivedPassword">Derived password</param> /// <param name="fileEntry">File entry to add</param> /// <param name="keyIdentifier">Key identifier</param> /// <param name="algorithm">Symmetric Encryption Algorithm to use</param> /// <returns>Tuple that tells if add was success, and possible error</returns> public (bool success, string possibleError) AddFileEntrySecret(byte[] derivedPassword, FileEntry fileEntry, string keyIdentifier, SymmetricEncryptionAlgorithm algorithm = SymmetricEncryptionAlgorithm.AES_CTR) { (bool checkResult, string possibleError) = MandatoryChecks(fileEntry, "FileEntry", keyIdentifier, derivedPassword); if (!checkResult) { return(checkResult, possibleError); } SymmetricKeyAlgorithm ska = SymmetricKeyAlgorithm.GenerateNew(algorithm); this.fileSecrets.Add(new FileEntrySecret(fileEntry, keyIdentifier, ska, derivedPassword)); return(success : true, possibleError : ""); }
/// <summary> /// Add payment card to Common secret container /// </summary> /// <param name="derivedPassword">Derived password</param> /// <param name="paymentCard">Payment card to add</param> /// <param name="keyIdentifier">Key identifier</param> /// <param name="algorithm">Symmetric Encryption Algorithm to use</param> /// <returns>Tuple that tells if add was success, and possible error</returns> public (bool success, string possibleError) AddPaymentCardSecret(byte[] derivedPassword, PaymentCard paymentCard, string keyIdentifier, SymmetricEncryptionAlgorithm algorithm = SymmetricEncryptionAlgorithm.AES_CTR) { (bool checkResult, string possibleError) = MandatoryChecks(paymentCard, "PaymentCard", keyIdentifier, derivedPassword); if (!checkResult) { return(checkResult, possibleError); } SymmetricKeyAlgorithm ska = SymmetricKeyAlgorithm.GenerateNew(algorithm); this.paymentCardSecrets.Add(new PaymentCardSecret(paymentCard, keyIdentifier, ska, derivedPassword)); return(success : true, possibleError : ""); }
/// <summary> /// Replace existing contact in Common secret container with another one (basically for editing purposes) /// </summary> /// <param name="zeroBasedIndex">Zero based index of contact secret that will be replaced</param> /// <param name="password">Plaintext password</param> /// <param name="contact">Contact to add</param> /// <param name="keyIdentifier">Key identifier</param> /// <param name="algorithm">Symmetric Encryption Algorithm to use</param> /// <returns>Tuple that tells if add was success, and possible error</returns> public (bool success, string possibleError) ReplaceContactSecret(int zeroBasedIndex, string password, Contact contact, string keyIdentifier, SymmetricEncryptionAlgorithm algorithm = SymmetricEncryptionAlgorithm.AES_CTR) { if (zeroBasedIndex < 0 || zeroBasedIndex >= this.contactSecrets.Count) { return(false, $"Index {zeroBasedIndex} is out of bounds [0, {this.contactSecrets.Count})"); } (bool checkResult, string possibleError) = MandatoryChecks(contact, "Contact", keyIdentifier, password); if (!checkResult) { return(checkResult, possibleError); } SymmetricKeyAlgorithm ska = SymmetricKeyAlgorithm.GenerateNew(algorithm); byte[] derivedPassword = this.FindKeyDerivationFunctionEntryWithKeyIdentifier(keyIdentifier).GeneratePasswordBytes(password); this.contactSecrets[zeroBasedIndex] = new ContactSecret(contact, keyIdentifier, ska, derivedPassword); return(success : true, possibleError : ""); }
/// <summary> /// Replace existing payment card in Common secret container with another one (basically for editing purposes) /// </summary> /// <param name="zeroBasedIndex">Zero based index of payment card secret that will be replaced</param> /// <param name="derivedPassword">Derived password</param> /// <param name="paymentCard">Payment card to add</param> /// <param name="keyIdentifier">Key identifier</param> /// <param name="algorithm">Symmetric Encryption Algorithm to use</param> /// <returns>Tuple that tells if add was success, and possible error</returns> public (bool success, string possibleError) ReplacePaymentCardSecret(int zeroBasedIndex, byte[] derivedPassword, PaymentCard paymentCard, string keyIdentifier, SymmetricEncryptionAlgorithm algorithm = SymmetricEncryptionAlgorithm.AES_CTR) { if (zeroBasedIndex < 0 || zeroBasedIndex >= this.paymentCardSecrets.Count) { return(false, $"Index {zeroBasedIndex} is out of bounds [0, {this.paymentCardSecrets.Count})"); } (bool checkResult, string possibleError) = MandatoryChecks(paymentCard, "PaymentCard", keyIdentifier, derivedPassword); if (!checkResult) { return(checkResult, possibleError); } SymmetricKeyAlgorithm ska = SymmetricKeyAlgorithm.GenerateNew(algorithm); this.paymentCardSecrets[zeroBasedIndex] = new PaymentCardSecret(paymentCard, keyIdentifier, ska, derivedPassword); return(success : true, possibleError : ""); }
/// <summary> /// Generate new SymmetricKeyAlgorithm, you should use this instead of constructor /// </summary> /// <param name="symmetricEncryptionAlgorithm">Wanted Symmetric encryption algorithm</param> /// <returns>SymmetricKeyAlgorithm</returns> public static SymmetricKeyAlgorithm GenerateNew(SymmetricEncryptionAlgorithm symmetricEncryptionAlgorithm) { return(new SymmetricKeyAlgorithm(symmetricEncryptionAlgorithm, 256, (symmetricEncryptionAlgorithm == SymmetricEncryptionAlgorithm.AES_CTR) ? (object)SettingsAES_CTR.CreateWithCryptographicRandomNumbers() : (object)SettingsChaCha20.CreateWithCryptographicRandomNumbers())); }
/// <summary> /// Add login information secret to Common secret container /// </summary> /// <param name="derivedPassword">Derived password</param> /// <param name="loginInformation">Loginiformation to add</param> /// <param name="keyIdentifier">Key identifier</param> /// <param name="algorithm">Symmetric Encryption Algorithm to use</param> /// <returns>Tuple that tells if add was success, and possible error</returns> public (bool success, string possibleError) AddLoginInformationSecret(byte[] derivedPassword, LoginInformation loginInformation, string keyIdentifier, SymmetricEncryptionAlgorithm algorithm = SymmetricEncryptionAlgorithm.AES_CTR) { (bool checkResult, string possibleError) = MandatoryChecks(loginInformation, "LoginInformation", keyIdentifier, derivedPassword); if (!checkResult) { return(checkResult, possibleError); } SymmetricKeyAlgorithm ska = SymmetricKeyAlgorithm.GenerateNew(algorithm); this.loginInformationSecrets.Add(new LoginInformationSecret(loginInformation, keyIdentifier, ska, derivedPassword)); return(success : true, possibleError : ""); }