public CryptoConfig(IKdfConfig kdfConfig, CipherModeType cipherMode, IvGenerationModeType ivGenerationMode, SignatureModeType signatureMode) { KdfConfig = kdfConfig; CipherMode = cipherMode; IvGenerationMode = ivGenerationMode; SignatureMode = signatureMode; }
public byte[] GetOrDerive(byte[] password, byte[] salt, IKdfConfig config) { var id = config.GetUniqueId(password, salt); if (_cache.TryGetValue(id, out var key)) { return(key); } key = config.Derive(password, salt); _cache[id] = key; return(key); }
public static Blob ParseFlexibleBlob(byte[] blob) { // Pieces of the string joined with $ ($1$argon2d$16$3$32768$2$aes256$cbchmac$16$...) // This part is the key derivation configuration: // - $1 - version, must be 1 // - $argon2d - method, must be "argon2d" or "pbkdf2" // // For argon2d: // - $16 - salt length // - $3 - time cost // - $32768 - memory cost // - $2 - parallelism // // For pbkdf2: // - $16 - salt length // - $10000 - number of iterations // - $sha256 - hash method // // The next part is the cipher/encryption configuration: // - $aes256 - cipher, must be aes256 // - $cbchmac - AES mode, must be cbchmac, cbc or gcm // - $16 - IV length // // Signature is always "hmac" // IV derivation could be either "data" or "evpByteToKey" // // After the crypto configuration: // - salt - "salt length" bytes // - IV - "IV length" bytes // - MAC - 32 bytes // - ciphertext - the rest var offset = 1; var version = GetNextComponent(blob, ref offset); if (version != "1") { throw new InternalErrorException($"Unsupported version: {version}"); } IKdfConfig kdfConfig = null; var method = GetNextComponent(blob, ref offset); switch (method) { case "argon2d": { var saltLength = int.Parse(GetNextComponent(blob, ref offset)); var timeCost = int.Parse(GetNextComponent(blob, ref offset)); var memoryCost = int.Parse(GetNextComponent(blob, ref offset)); var parallelism = int.Parse(GetNextComponent(blob, ref offset)); kdfConfig = new Argon2dConfig(memoryCost: memoryCost, timeCost: timeCost, parallelism: parallelism, saltLength: saltLength); } break; case "pbkdf2": { var saltLength = int.Parse(GetNextComponent(blob, ref offset)); var iterations = int.Parse(GetNextComponent(blob, ref offset)); Pbkdf2Config.HashMethodType hashMethod; string hashMethodStr = GetNextComponent(blob, ref offset); switch (hashMethodStr) { case "sha1": hashMethod = Pbkdf2Config.HashMethodType.Sha1; break; case "sha256": hashMethod = Pbkdf2Config.HashMethodType.Sha256; break; default: throw new InternalErrorException($"Unknown PBKDF2 hashing method: {hashMethodStr}"); } kdfConfig = new Pbkdf2Config(hashMethod: hashMethod, iterations: iterations, saltLength: saltLength); } break; default: throw new InternalErrorException($"Unexpected hashing method: {method}"); } var cipher = GetNextComponent(blob, ref offset); if (cipher != "aes256") { throw new InternalErrorException($"Unexpected cipher: {cipher}"); } CryptoConfig.CipherModeType cipherMode; var cipherModeStr = GetNextComponent(blob, ref offset); switch (cipherModeStr) { case "cbc": cipherMode = CryptoConfig.CipherModeType.Cbc; break; case "cbchmac": cipherMode = CryptoConfig.CipherModeType.CbcHmac; break; case "gcm": cipherMode = CryptoConfig.CipherModeType.Gcm; break; default: throw new InternalErrorException($"Unknown cipher mode: {cipherModeStr}"); } var cryptoConfig = new CryptoConfig(kdfConfig, cipherMode, CryptoConfig.IvGenerationModeType.Data, CryptoConfig.SignatureModeType.HmacSha256); var ivLength = int.Parse(GetNextComponent(blob, ref offset)); var salt = blob.Sub(offset, kdfConfig.SaltLength); offset += kdfConfig.SaltLength; var iv = blob.Sub(offset, ivLength); offset += ivLength; var hash = blob.Sub(offset, 32); offset += 32; var ciphertext = blob.Sub(offset, int.MaxValue); return(new Blob(ciphertext: ciphertext, salt: salt, iv: iv, hash: hash, cryptoConfig: cryptoConfig)); }