public static void Save(AnsibleVaultFile f, TextWriter output, string label, int width = 80) { if (string.IsNullOrEmpty(f.Label)) { output.WriteLine($"{AnsibleVaultSignature};{f.Version};{f.Algorithm}"); } else { output.WriteLine($"{AnsibleVaultSignature};{f.Version};{f.Algorithm};{f.Label}"); } var data = new byte[f.Salt.Length * 2 + f.ExpectedHMac.Length * 2 + f.EncryptedBytes.Length * 2 + 2]; var dataSpan = data.AsSpan(); Encoding.ASCII.GetBytes(ByteUtil.ConvertToHexString(f.Salt)).AsSpan().CopyTo(dataSpan); dataSpan[f.Salt.Length * 2] = 0x0a; Encoding.ASCII.GetBytes(ByteUtil.ConvertToHexString(f.ExpectedHMac)).AsSpan().CopyTo(dataSpan.Slice(f.Salt.Length * 2 + 1)); dataSpan[f.Salt.Length * 2 + 1 + f.ExpectedHMac.Length * 2] = 0x0a; Encoding.ASCII.GetBytes(ByteUtil.ConvertToHexString(f.EncryptedBytes)).AsSpan().CopyTo(dataSpan.Slice(f.Salt.Length * 2 + f.ExpectedHMac.Length * 2 + 2)); Span <char> buffer = stackalloc char[width]; while (!dataSpan.IsEmpty) { var len = Math.Min(40, dataSpan.Length); ByteUtil.ConvertToHexChars(dataSpan.Slice(0, len), buffer); output.WriteLine(buffer.Slice(0, len * 2)); dataSpan = dataSpan.Slice(len); } }
public static AnsibleVaultFile Load(TextReader sr) { var ret = new AnsibleVaultFile(); var headerString = sr.ReadLine(); var header = headerString.Split(';'); if (header[0] != AnsibleVaultSignature) { throw new ArgumentException($"invalid ansible vault header:{headerString}"); } ret.Version = header[1]; ret.Algorithm = header[2]; if (header.Length > 3) { ret.Label = header[3]; } var bodyBytes = new List <byte>(); while (true) { var line = sr.ReadLine(); if (line == null) { break; } ByteUtil.ConvertToBytes(line, bodyBytes); } var(salt, expectedhmac, encrypted_bytes) = DecodeBody(bodyBytes.ToArray()); ret.Salt = salt; ret.ExpectedHMac = expectedhmac; ret.EncryptedBytes = encrypted_bytes; return(ret); }
public void Encode(byte[] data, byte[] password, byte[] salt, TextWriter output, string label, int width) { var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA256); var derived = pbkdf2.GetBytes(32 + 32 + 16); var vaultFile = new AnsibleVaultFile(); vaultFile.Version = "1.1"; vaultFile.Algorithm = "AES256"; vaultFile.Salt = salt; var cipher = CipherUtilities.GetCipher("AES/CTR/PKCS7Padding"); var cipherKeyBytes = derived.AsSpan(0, 32).ToArray(); var hmacKey = derived.AsSpan(32, 32).ToArray(); var iv = derived.AsSpan(64, 16).ToArray(); var cparam = new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", cipherKeyBytes), iv); cipher.Init(true, cparam); var encrypted = cipher.DoFinal(data); var hmac256 = new HMACSHA256(hmacKey); vaultFile.EncryptedBytes = encrypted; vaultFile.ExpectedHMac = hmac256.ComputeHash(encrypted); AnsibleVaultFile.Save(vaultFile, output, label, width); }
public void Decode(TextReader vaultFileReader, byte[] password, Stream output) { var vaultFile = AnsibleVaultFile.Load(vaultFileReader); var cipher = CipherUtilities.GetCipher("AES/CTR/PKCS7Padding"); var pbkdf2 = new Rfc2898DeriveBytes(password, vaultFile.Salt, 10000, HashAlgorithmName.SHA256); var derived = pbkdf2.GetBytes(32 + 32 + 16); var cipherKeyBytes = derived.AsSpan(0, 32).ToArray(); var hmacKey = derived.AsSpan(32, 32).ToArray(); var iv = derived.AsSpan(64, 16).ToArray(); var hmac256 = new HMACSHA256(hmacKey); var actualhmac = hmac256.ComputeHash(vaultFile.EncryptedBytes); if (!actualhmac.AsSpan().SequenceEqual(vaultFile.ExpectedHMac)) { throw new InvalidKeyException("HMAC check error: invalid password"); } var cparam = new ParametersWithIV(ParameterUtilities.CreateKeyParameter("AES", cipherKeyBytes), iv); cipher.Init(false, cparam); var decrypted = cipher.DoFinal(vaultFile.EncryptedBytes); output.Write(decrypted.AsSpan()); }