private static byte[] Decrypt(NppCryptCipherParams cipher, byte[] encryptedData, string password) { if (cipher.Encryption.Cipher != "rijndael") { throw new Exception($"Cipher algorithm \"{cipher.Encryption.Cipher}\" is not supported now. " + "Only \"rijndael\" algorithm might be used in the current version"); } if (cipher.Encryption.Mode != CipherMode.CBC) { throw new Exception($"Cipher algorithm mode \"{cipher.Encryption.Mode}\" is not supported now. " + $"Only \"{nameof(CipherMode.CBC)}\" mode might be used in the current version"); } if (cipher.Key.Algorithm != "scrypt") { throw new Exception($"Key hashing algorithm \"{cipher.Key.Algorithm}\" is not supported now. " + "Only \"scrypt\" algorithm might be used in the current version"); } if (!cipher.Key.N.HasValue) { throw new Exception($"Parameter '{nameof(cipher.Key.N)}' of key hashing algorithm is not set"); } if (!cipher.Key.R.HasValue) { throw new Exception($"Parameter '{nameof(cipher.Key.R)}' of key hashing algorithm is not set"); } if (!cipher.Key.P.HasValue) { throw new Exception($"Parameter '{nameof(cipher.Key.P)}' of key hashing algorithm is not set"); } if (cipher.Key.Salt == null) { throw new Exception($"Parameter '{nameof(cipher.Key.Salt)}' of key hashing algorithm is not set"); } var key = ScryptEncoder.CryptoScrypt(Encoding.UTF8.GetBytes(password), cipher.Key.Salt, cipher.Key.N.Value, cipher.Key.R.Value, cipher.Key.P.Value, cipher.Encryption.KeyLength ?? 32); using Rijndael rijAlg = Rijndael.Create(); rijAlg.Key = key; rijAlg.IV = cipher.Iv.Value; rijAlg.Mode = cipher.Encryption.Mode; using var ms = new MemoryStream(); using var cs = new CryptoStream(ms, rijAlg.CreateDecryptor(), CryptoStreamMode.Write); cs.Write(encryptedData, 0, encryptedData.Length); cs.Close(); var res = ms.ToArray(); ms.Close(); return(res); }
private static NppCryptCipherParams ParseCipherParams(string nppCryptXml) { XmlDocument doc; try { doc = new XmlDocument(); doc.LoadXml(nppCryptXml); } catch (Exception e) { throw new Exception("NppCrypt-header parsing exception", e); } var res = new NppCryptCipherParams { Encryption = new NppCryptEncryptionParams(), Key = new NppCryptKeyParams(), Iv = new NppCryptIvParams() }; XmlNode getTag(XmlNode parent, string tagName) { using (var tagCollection = (parent as XmlElement)?.GetElementsByTagName(tagName)) { if (tagCollection?.Count != 1) { throw new Exception($"NppCrypt-header parsing exception. The \"<{tagName}>\" tag was not found " + "or is present in several instances"); } return(tagCollection[0]); } } string getAttribute(XmlNode parent, string attributeName) { return(parent?.Attributes?[attributeName]?.Value); } byte[] parseBase64String(string str) { try { return(Convert.FromBase64String(str)); } catch { return(null); } } CipherMode parseMode(string mode) { var m = mode.Trim().ToUpperInvariant(); var modes = Enum.GetValues(typeof(CipherMode)).Cast <CipherMode>().ToList(); foreach (var cipherMode in modes) { if (cipherMode.ToString().ToUpperInvariant() == m) { return(cipherMode); } } throw new Exception($"Unknown cipher mode '{mode}'"); } var encryptionTag = getTag(doc.DocumentElement, "encryption"); res.Encryption.Cipher = getAttribute(encryptionTag, "cipher"); if (int.TryParse(getAttribute(encryptionTag, "key-length"), out int keyLen)) { res.Encryption.KeyLength = keyLen; } res.Encryption.Mode = parseMode(getAttribute(encryptionTag, "mode")); res.Encryption.Encoding = getAttribute(encryptionTag, "encoding"); var keyTag = getTag(doc.DocumentElement, "key"); res.Key.Algorithm = getAttribute(keyTag, "algorithm"); if (int.TryParse(getAttribute(keyTag, "N"), out int n)) { res.Key.N = n; } if (int.TryParse(getAttribute(keyTag, "r"), out int r)) { res.Key.R = r; } if (int.TryParse(getAttribute(keyTag, "p"), out int p)) { res.Key.P = p; } res.Key.Salt = parseBase64String(getAttribute(keyTag, "salt")); var ivTag = getTag(doc.DocumentElement, "iv"); res.Iv.Value = parseBase64String(getAttribute(ivTag, "value")); res.Iv.Method = getAttribute(ivTag, "method"); return(res); }