/* $Id: XmlEnc_DecryptXml.cs $
* Last updated:
* $Date: 2020-12-07 03:17:00 $
* $Version: 1.0.0 $
*/
/* Ref:
* [Using CryptoSys PKI to encrypt and decrypt using XMLENC](https://cryptosys.net/pki/xmlenc-encrypt-decrypt.html)
*/
using System;
using System.Text;
using System.Diagnostics;
using CryptoSysPKI;
/******************************* LICENSE ***********************************
* Copyright (C) 2020 David Ireland, DI Management Services Pty Limited.
* All rights reserved. <https://di-mgt.com.au> <https://cryptosys.net>
* The code in this module is licensed under the terms of the MIT license.
* For a copy, see <http://opensource.org/licenses/MIT>
****************************************************************************
*/
namespace XmlEnc
{
class XmlEnc_DecryptXml
{
static void Main(string[] args)
{
string cipherValue;
string s;
Console.WriteLine("PKI Version={0}", General.Version());
/////////////////////////////////
// Decrypt block cipher CBC mode
/////////////////////////////////
// FILE: encrypt-data-aes128-cbc.xml
cipherValue = "QMpxhXq1DtBeyC9KfSaMQWrEtefe+e935gF/x62spvmL6IW0XeS0W4Kk31OgWzN0";
s = xmlenc_decrypt_cbc_data(cipherValue, "6162636465666768696A6B6C6D6E6F70", CipherAlgorithm.Aes128);
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
// Same again as a one-liner
s = System.Text.Encoding.UTF8.GetString(Cipher.Decrypt(
Cnv.FromBase64("QMpxhXq1DtBeyC9KfSaMQWrEtefe+e935gF/x62spvmL6IW0XeS0W4Kk31OgWzN0"),
Cnv.FromHex("6162636465666768696A6B6C6D6E6F70"), null,
CipherAlgorithm.Aes128, Mode.CBC, Padding.W3CPadding, Cipher.Opts.PrefixIV));
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
// FILE: encrypt-data-aes192-cbc-kw-aes256.xml
cipherValue = "50lv94d/DFJirJXYOUXaBlrO+7gIXpx8cqH+G2xvE4mueoIxmGs8RH7FBXwjuMgf";
s = xmlenc_decrypt_cbc_data(cipherValue, "F65CD2C48C1DA5565ED0AAB2D042713373C74C8E69332F2F", CipherAlgorithm.Aes192);
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
// FILE: encrypt-element-aes128-cbc-rsa-1_5.xml
cipherValue = @"0wkECpTy60/FDwbVM4zgd9qJVjR4h0q4PLm5pyyIxAuhbEh0art03yEikmbWBt2H
7qOk2G9iufUdwwqNPuZV5Qw5Rg2FMvTx234lDERGn5p+hhjOTcss5JF9QDzgdiec
KABX3vbCESi/f3uwQ8BYDT+6SnxTR+xtcNv5xhbUCIFk/TaenSWx6p6fntTwTl1e
lpwnI0EtM1yf4a9tBiH9PNd36BUv2rvSi4cZvJqSB3ZKvGtuwwyRzOzlzl259d1u
QuoYysTBEAHw/WIop8eAexU9PUv7UbTkQAQag1yStda+GepVdpXEpu4hcxXQcvfs
9AQgkAgh4JKrnY4Bhz2B/e4CHHfbEedDOi+FVYlZuLn0CzrKMnM+1nUmqxJVWHz7
hytidpuqNRw3gcMkYvgH6g==";
s = xmlenc_decrypt_cbc_data(cipherValue, "493185CE8177AC09C4DE6C7C75524B16", CipherAlgorithm.Aes128);
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
// FILE: encrypt-element-aes256-cbc-carried-kw-aes256.xml
cipherValue = @"pdDtiyd7XQ/BFEEN0PMJuHnLUfCY+bJlsW+q04OiKSPnRd4/dS1tjaTfj5dPpGXe
cY3fJvRsq9QP1CJiwyEC/EQ1zSLbzwOtZ+NtxtsFgYvPBJ9t86ZcXIjlErQ85z3L
wnb8rSHpE9tu4tJ1rjgf2i6NCbdFnSMXLSDgLEs48+gkX0cJCmKxzRaSE4cV0OSl
hBWND4EYzX1M679VlSYrI0de+lSPO3Vx+y/TuZ5Vo+uu9+YP+ce0LRkx2BicjjsP
QO9sp+yjHPNDIV1Z7VHsDIWqqmBaNQo3GuzF5WzWgaXTKnPv/IgUQn+1t3EtgHyb
JhnfR/1em16z/Zaf9Uy1Lfd//yfEJ9BCjqwe1UjwN6ytu1v2BHd+8bVjD2o+Dg8V
7ayOLlkWOTOLvtJMPOXPqw==";
s = xmlenc_decrypt_cbc_data(cipherValue, "41559545888C22BF367F7936E6A9FFB6D810B2AB42BF70220F2168DB9B503DC6", CipherAlgorithm.Aes256);
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
/////////////////////////////////////
// Decrypt block cipher AES-GCM mode
/////////////////////////////////////
// FILE: encrypt-data-aes256-gcm.xml
cipherValue = "AQIDBAUGBwgJCgsMqYHeLKkzx8/iBLZa8f+ZCMGHulqDdiELj+ghwhU1jg62WW0=";
s = xmlenc_decrypt_gcm(cipherValue, "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435", AeadAlgorithm.Aes_256_Gcm);
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
// Same again as a one-liner
s = System.Text.Encoding.UTF8.GetString(Cipher.DecryptAEAD(
Cnv.FromBase64("AQIDBAUGBwgJCgsMqYHeLKkzx8/iBLZa8f+ZCMGHulqDdiELj+ghwhU1jg62WW0="),
Cnv.FromHex("6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435"), null, null,
AeadAlgorithm.Aes_256_Gcm, Cipher.Opts.PrefixIV));
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
// FILE: root-bob-oaep-gcm.xml
cipherValue = "f4K4iAry8y7hz2mKl3Xpqnx5lVPTKkeKhM7PmGJITVE5pk4NZjFak1ZaKpgvoi3ooUP+sxUArXnNG/GrLYQ=";
s = xmlenc_decrypt_gcm(cipherValue, "E2493529B46E23907FC77AB0C4DD74BE", AeadAlgorithm.Aes_128_Gcm);
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
// FILE: root-oaep-256-gcm-x2.xml
cipherValue = "e2kl8SXHPvyy/qbzY2Rk46+6vWtTLgt4rSL+1IMkdJqBQvpqaMPFeKa4k4yxsa4XauwZZYdOIfwj13sFvMA=";
s = xmlenc_decrypt_gcm(cipherValue, "F45F70F9645F73B3CB88DBD17EBA881B", AeadAlgorithm.Aes_128_Gcm);
Console.WriteLine("PT='{0}'", s);
Debug.Assert(s.Length > 0);
/////////////////////////////////////
// Decrypt key wrap
/////////////////////////////////////
// FILE: encrypt-data-aes192-cbc-kw-aes256.xml
cipherValue = "4AAgyi3M7xNdBimbQZKdGJLn3/cS4Yv8QKuA01+gUnY=";
s = xmlenc_decrypt_kw_keyhex(cipherValue, "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435", CipherAlgorithm.Aes256);
Console.WriteLine("CEK=0x{0}", s);
Debug.Assert(s.Length > 0);
// Same again as a one-liner
s = Cnv.ToHex(Cipher.KeyUnwrap(
Cnv.FromBase64("4AAgyi3M7xNdBimbQZKdGJLn3/cS4Yv8QKuA01+gUnY="),
Cnv.FromHex("6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435"), CipherAlgorithm.Aes256));
Console.WriteLine("CEK=0x{0}", s);
Debug.Assert(s.Length > 0);
// FILE: encrypt-element-aes256-cbc-carried-kw-aes256.xml
cipherValue = "bsL63D0hPN6EOyzdgfEmKsAAvoJiGM+Wp9a9KZM92IKdl7s3YSntRg==";
s = xmlenc_decrypt_kw_keyhex(cipherValue, "6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435", CipherAlgorithm.Aes256);
Console.WriteLine("CEK=0x{0}", s);
Debug.Assert(s.Length > 0);
/////////////////////////////////////
// Decrypt key rsa-1_5
/////////////////////////////////////
// FILE: encrypt-element-aes128-cbc-rsa-1_5.xml
cipherValue = @"heZshNX5m7arS3OmR72+8WNCMMpznxE41dLWkgd6XJpzl+IN2xuijAf4YPEjjJmZ
nt9PlO3/hiHl0Cvpg5vMR6AhvL49BvCz9JCeMG6x3MHBiKbRNhyEq2rX7o1GdJhC
5cm35Q/ZDKV9DHG8jWmPcOb8yKU9NYo2LJKDb3YHOJY=";
s = xmlenc_decrypt_rsa_15_keyhex(cipherValue, "rsa-w3c.p8", "");
Console.WriteLine("CEK=0x{0}", s);
Debug.Assert(s.Length > 0);
// Same again as a one-liner
s = Cnv.ToHex(Rsa.Decrypt(Cnv.FromBase64(@"heZshNX5m7arS3OmR72+8WNCMMpznxE41dLWkgd6XJpzl+IN2xuijAf4YPEjjJmZ
nt9PlO3/hiHl0Cvpg5vMR6AhvL49BvCz9JCeMG6x3MHBiKbRNhyEq2rX7o1GdJhC
5cm35Q/ZDKV9DHG8jWmPcOb8yKU9NYo2LJKDb3YHOJY="), "rsa-w3c.p8", ""));
Console.WriteLine("CEK=0x{0}", s);
Debug.Assert(s.Length > 0);
/////////////////////////////////////
// Decrypt key rsa-oaep
/////////////////////////////////////
// FILE: root-bob-oaep-gcm.xml
cipherValue = @"ne3BEmELlWOKCvevCnKmgZ9//JYNgSrtdighAztmUJAtuGCXWMqtfsSLccTUpEdm
k4Vl+BampcxIiEvHduNkq1un9oV7ikyrTiT0A9jChlC8Tf8HU9XeU3I/I/5FqP8V
IxWfnTLuvu/jp4lVyqoNmDtsooqlQtcaC0C7JRoc+bKeqMhzZxOgdUK3UM34aDDk
HZHZSaMbWp8P59kJLUECMXTP+dW3q8MMucr7PEGhN5VGBKNH3/IlCvDvg3ROW/cY
csCTh8Vve5h+eyiZUl2DcBITgj31qFkZ/QJtzoIG7PbkS5WU0NNtAguO6z7MbZlv
PAOyQgvJpmSQqKUOrHro8g==";
s = xmlenc_decrypt_rsa_oaep_keyhex(cipherValue, "bob-smime.p8", "", Rsa.HashAlg.Sha256, Rsa.AdvOptions.Mgf1_Sha1);
Console.WriteLine("CEK=0x{0}", s);
Debug.Assert(s.Length > 0);
// FILE: root-oaep-256-gcm-x2.xml
cipherValue = @"qsIPCYkqgCSDv+xxNf0swqJiDZiVTsPrMdPcPFeaZW+yK3KqeHYHZubrTMV0Cj5b
gezvKe/fq+OdIZVvxIDR/nJy0M/Jm6GiVnOmm2FzzP9YnsARubF2piwGGT5bo4a0
wkoH+bBBcZEMPG1LHWBUThBn+pz6ApV/ogLB4q5f5bkiqKSi4rZktT8fxxJJvqdg
lrYmLNSM+QS51YP35xtBwMups8BTHNQ/n+YOoz0/X3xBMIgCc0K0W14LG9qgXsgR
AVtxezJkiOq8q+jj12vNyBLqQoR3MnTaOM9kmHcwHFkCoG4HBgDTQJWOd2oIrHGi
2TfIvBsPHXk6STZKEj7u4A==";
s = xmlenc_decrypt_rsa_oaep_keyhex(cipherValue, "bob-smime.p8", "", Rsa.HashAlg.Sha256);
Console.WriteLine("CEK=0x{0}", s);
Debug.Assert(s.Length > 0);
}
/// <summary>
/// Decrypt base64-encoded CipherValue using block cipher in CBC mode as per W3C XMLENC.
/// </summary>
/// <param name="cipherValue">Base64-encoded CipherValue</param>
/// <param name="keyHex">Key in hex encoding of exact required length for algorithm (16|24|32 bytes)</param>
/// <param name="cipherAlg">Block cipher algorithm</param>
/// <returns>Decrypted plaintext as a Unicode string or the empty string on error.</returns>
static string xmlenc_decrypt_cbc_data(string cipherValue, string keyHex, CipherAlgorithm cipherAlg)
{
byte[] pt = Cipher.Decrypt(Cnv.FromBase64(cipherValue), Cnv.FromHex(keyHex), null, cipherAlg, Mode.CBC, Padding.W3CPadding, Cipher.Opts.PrefixIV);
return System.Text.Encoding.UTF8.GetString(pt);
}
/// <summary>
/// Decrypt base64-encoded CipherValue using block cipher in AES-GCM mode as per W3C XMLENC.
/// </summary>
/// <param name="cipherValue">Base64-encoded CipherValue</param>
/// <param name="keyHex">Key in hex encoding of exact required length for algorithm (16|24|32 bytes)</param>
/// <param name="aeadAlg">Authenticated encryption algorithm</param>
/// <returns>Decrypted plaintext as a Unicode string or the empty string on error.</returns>
static string xmlenc_decrypt_gcm(string cipherValue, string keyHex, AeadAlgorithm aeadAlg)
{
byte[] pt = Cipher.DecryptAEAD(Cnv.FromBase64(cipherValue), Cnv.FromHex(keyHex), null, null, aeadAlg, Cipher.Opts.PrefixIV);
return System.Text.Encoding.UTF8.GetString(pt);
}
/// <summary>
/// Decrypt key wrap material.
/// </summary>
/// <param name="cipherValue">Base64-encoded CipherValue</param>
/// <param name="kekHex">Key-encryption key (KEK) encoded in hex of exact required length for algorithm (16|24|32 bytes)</param>
/// <param name="cipherAlg">Cipher algorithm</param>
/// <returns>Key material encoded in hex.</returns>
static string xmlenc_decrypt_kw_keyhex(string cipherValue, string kekHex, CipherAlgorithm cipherAlg)
{
byte[] key = Cipher.KeyUnwrap(Cnv.FromBase64(cipherValue), Cnv.FromHex(kekHex), cipherAlg);
return Cnv.ToHex(key);
}
/// <summary>
/// Decrypt key encrypted using RSA PKCS#1 v1.5 key transport algorithm.
/// </summary>
/// <param name="cipherValue">Base64-encoded CipherValue</param>
/// <param name="rsaKeyFile">File containing RSA private key or a string containing the key in PEM format.</param>
/// <param name="password">Password for key file or <c>""</c> if not required.</param>
/// <returns>Key material encoded in hex.</returns>
static string xmlenc_decrypt_rsa_15_keyhex(string cipherValue, string rsaKeyFile, string password = "")
{
byte[] key = Rsa.Decrypt(Cnv.FromBase64(cipherValue), rsaKeyFile, password);
return Cnv.ToHex(key);
}
/// <summary>
/// Decrypt key encrypted using RSA-OAEP key transport algorithm.
/// </summary>
/// <param name="cipherValue">Base64-encoded CipherValue</param>
/// <param name="rsaKeyFile">File containing RSA private key or a string containing the key in PEM format.</param>
/// <param name="password">Password for key file or <c>""</c> if not required.</param>
/// <param name="hashAlg">Hash function for EME-OAEP encoding, otherwise ignored. [default = SHA-1]</param>
/// <param name="advOpts"><c>Mgf1_Sha1</c> to force the MGF hash function to be SHA-1 [default = same as hash function set by <c>hashAlg</c>]</param>
/// <returns>Key material encoded in hex.</returns>
static string xmlenc_decrypt_rsa_oaep_keyhex(string cipherValue, string rsaKeyFile, string password = "", Rsa.HashAlg hashAlg = Rsa.HashAlg.Sha1, Rsa.AdvOptions advOpts = Rsa.AdvOptions.Default)
{
byte[] key = Rsa.Decrypt(Cnv.FromBase64(cipherValue), rsaKeyFile, password, Rsa.EME.OAEP, hashAlg, advOpts);
return Cnv.ToHex(key);
}
}
}