internal static KeyMac DecryptAccountKey(M.Item encryptedItem, KeyMac masterKey) { var raw = encryptedItem.Key.Decode64(); if (raw.Length != 112) { throw CorruptedError("key has invalid size"); } using var io = new BinaryReader(new MemoryStream(raw, false)); var iv = io.ReadBytes(16); var ciphertext = io.ReadBytes(64); var storedTag = io.ReadBytes(32); // Rewind and reread everything to the tag io.BaseStream.Seek(0, SeekOrigin.Begin); var hashedContent = io.ReadBytes(80); var computedTag = Crypto.HmacSha256(masterKey.MacKey, hashedContent); if (!computedTag.SequenceEqual(storedTag)) { throw CorruptedError("key tag doesn't match"); } return(new KeyMac(Util.DecryptAes(ciphertext, iv, masterKey))); }
internal static Account[] DecryptAccounts(M.Item[] encryptedItems, KeyMac masterKey, KeyMac overviewKey, Dictionary <string, Folder> folders) { return(encryptedItems .Where(i => !i.Deleted) .Where(i => i.Category == "001") .Select(i => DecryptAccount(i, masterKey, overviewKey, folders)) .ToArray()); }
internal static T DecryptJson <T>(string encryptedJsonBase64, KeyMac key) { try { var json = Opdata01.Decrypt(encryptedJsonBase64, key).ToUtf8(); return(JsonConvert.DeserializeObject <T>(json)); } catch (JsonException e) { throw FormatError($"JSON: Invalid JSON schema for {typeof(T).Name}", e); } }
internal static KeyMac DecryptMasterKey(M.Profile profile, KeyMac kek) { try { return(DecryptBase64Key(profile.MasterKey, kek)); } catch (InternalErrorException e) when(e.Message.Contains("tag doesn't match")) { // This is a bit hacky. There's no sure way to verify if the password is correct. The things // will start failing to decrypt on HMAC/tag verification. So only for the master key we assume // that the structure of the vault is not corrupted (which is unlikely) but rather the master // password wasn't given correctly. So we rethrow the "corrupted" exception as the "incorrect // password". Unfortunately we have to rely on the contents of the error message as well. throw new BadCredentialsException("Most likely the master password is incorrect", e); } }
internal static Account DecryptAccount(M.Item encryptedItem, KeyMac masterKey, KeyMac overviewKey, Dictionary <string, Folder> folders) { var overview = DecryptAccountOverview(encryptedItem, overviewKey); var accountKey = DecryptAccountKey(encryptedItem, masterKey); var details = DecryptAccountDetails(encryptedItem, accountKey); return(new Account(id: encryptedItem.Id, name: overview.Title ?? "", username: FindDetailField(details, "username"), password: FindDetailField(details, "password"), url: overview.Url ?? "", note: details.Notes ?? "", folder: folders.GetOrDefault(encryptedItem.FolderId ?? "", Folder.None))); }
public static byte[] Decrypt(byte[] blob, KeyMac key) { if (blob.Length < 64) { throw CorruptedError("too short"); } using var io = new BinaryReader(new MemoryStream(blob)); var magic = io.ReadBytes(8); if (!magic.SequenceEqual("opdata01".ToBytes())) { throw CorruptedError("invalid signature"); } // TODO: Sloppy! Assume 2G should be enough. // TODO: Should be little endian! This will not work on big endian platform! var length = (int)io.ReadInt64(); var iv = io.ReadBytes(16); var padding = 16 - length % 16; if (blob.Length != 32 + padding + length + 32) { throw CorruptedError("invalid length"); } var ciphertext = io.ReadBytes(padding + length); var storedTag = io.ReadBytes(32); // Rewind and reread everything to the tag io.BaseStream.Seek(0, SeekOrigin.Begin); var hashedContent = io.ReadBytes(32 + padding + length); var computedTag = Crypto.HmacSha256(key.MacKey, hashedContent); if (!computedTag.SequenceEqual(storedTag)) { throw CorruptedError("tag doesn't match"); } var plaintext = Util.DecryptAes(ciphertext, iv, key); return(plaintext.Sub(padding, length)); }
public static byte[] DecryptAes(byte[] ciphertext, byte[] iv, KeyMac key) { return(Crypto.DecryptAes256CbcNoPadding(ciphertext, iv, key.Key)); }
internal static M.ItemDetails DecryptAccountDetails(M.Item encryptedItem, KeyMac accountKey) { return(DecryptJson <M.ItemDetails>(encryptedItem.Details, accountKey)); }
internal static M.ItemOverview DecryptAccountOverview(M.Item encryptedItem, KeyMac overviewKey) { return(DecryptJson <M.ItemOverview>(encryptedItem.Overview, overviewKey)); }
internal static Folder DecryptFolder(M.Folder folder, KeyMac overviewKey) { var overview = DecryptJson <M.FolderOverview>(folder.Overview, overviewKey); return(new Folder(folder.Id, overview.Title)); }
internal static Dictionary <string, Folder> DecryptFolders(M.Folder[] encryptedFolders, KeyMac overviewKey) { var activeFolders = encryptedFolders.Where(i => !i.Deleted).ToArray(); var childToParent = activeFolders.ToDictionary(i => i.Id, i => i.ParentId ?? ""); var folders = activeFolders.Select(i => DecryptFolder(i, overviewKey)).ToDictionary(i => i.Id); // Assign parent folders foreach (var i in folders) { var parentId = childToParent[i.Key]; if (folders.ContainsKey(parentId)) { i.Value.Parent = folders[parentId]; } } return(folders); }
internal static KeyMac DecryptBase64Key(string encryptedKeyBase64, KeyMac kek) { var raw = Opdata01.Decrypt(encryptedKeyBase64, kek); return(new KeyMac(Crypto.Sha512(raw))); }
internal static KeyMac DecryptOverviewKey(M.Profile profile, KeyMac kek) { return(DecryptBase64Key(profile.OverviewKey, kek)); }
public static byte[] Decrypt(string blobBase64, KeyMac key) { return(Decrypt(blobBase64.Decode64(), key)); }