Example #1
0
        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)));
        }
Example #2
0
 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());
 }
Example #3
0
 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);
     }
 }
Example #4
0
 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);
     }
 }
Example #5
0
        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)));
        }
Example #6
0
        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));
        }
Example #7
0
 public static byte[] DecryptAes(byte[] ciphertext, byte[] iv, KeyMac key)
 {
     return(Crypto.DecryptAes256CbcNoPadding(ciphertext, iv, key.Key));
 }
Example #8
0
 internal static M.ItemDetails DecryptAccountDetails(M.Item encryptedItem, KeyMac accountKey)
 {
     return(DecryptJson <M.ItemDetails>(encryptedItem.Details, accountKey));
 }
Example #9
0
 internal static M.ItemOverview DecryptAccountOverview(M.Item encryptedItem, KeyMac overviewKey)
 {
     return(DecryptJson <M.ItemOverview>(encryptedItem.Overview, overviewKey));
 }
Example #10
0
        internal static Folder DecryptFolder(M.Folder folder, KeyMac overviewKey)
        {
            var overview = DecryptJson <M.FolderOverview>(folder.Overview, overviewKey);

            return(new Folder(folder.Id, overview.Title));
        }
Example #11
0
        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);
        }
Example #12
0
        internal static KeyMac DecryptBase64Key(string encryptedKeyBase64, KeyMac kek)
        {
            var raw = Opdata01.Decrypt(encryptedKeyBase64, kek);

            return(new KeyMac(Crypto.Sha512(raw)));
        }
Example #13
0
 internal static KeyMac DecryptOverviewKey(M.Profile profile, KeyMac kek)
 {
     return(DecryptBase64Key(profile.OverviewKey, kek));
 }
Example #14
0
 public static byte[] Decrypt(string blobBase64, KeyMac key)
 {
     return(Decrypt(blobBase64.Decode64(), key));
 }