/// <summary> /// Peel the onion until we can return the original plain data. Remember that the calling environment must contain all /// necessary private keys. /// </summary> public byte[] PeelAll() { if (AsymmetricEncryptedKey == null) { throw new Exception( "AsymmetricEncryptedKey not found. Are you sure this onion doesn't have more layers?"); } byte[] plainData; var onion = this; while (!onion.IsRoot) { onion = onion.PeelOne(); } using (var aes = new AESCryptoAgent()) using (var rsa = new RSACryptoAgent(onion.AsymmetricThumbprint)) { var decryptedSymmetricKey = rsa.Decrypt(onion.AsymmetricEncryptedKey); plainData = aes.Decrypt(onion.SymmetricEncryptedData, decryptedSymmetricKey, onion.SymmetricAlgorithmIV); } return(plainData); }
/// <summary> /// N-level encryption of existing onion ctor /// </summary> public PublicKeyEncryptionOnion(PublicKeyEncryptionOnion innerOnion, string asymmetricThumbprint) { Mandate.That(innerOnion, nameof(innerOnion)).IsNotNull(); Mandate.That(asymmetricThumbprint, nameof(asymmetricThumbprint)).IsNotNullOrEmpty(); AsymmetricThumbprint = asymmetricThumbprint; InnerOnion = innerOnion.Clone(); // allocate a new object so we're self contained and the calling code can do whatever it wants with the parameter object InnerOnion.AsymmetricEncryptedKey = null; using (var aes = new AESCryptoAgent()) using (var rsa = new RSACryptoAgent(asymmetricThumbprint)) { // generate the aes key and use it to re-encrypt the original key var symmetricKey = aes.GenerateKey(); SymmetricAlgorithmIV = aes.GenerateIV(); SymmetricEncryptedData = aes.Encrypt(innerOnion.AsymmetricEncryptedKey, symmetricKey, SymmetricAlgorithmIV); // encrypt the aes key with the public key AsymmetricEncryptedKey = rsa.Encrypt(symmetricKey); } // even though we're not using the param onion, we don't want to let it retain the data that's at a lower level of encryption innerOnion.AsymmetricEncryptedKey = null; }
/// <summary> /// Return an onion with the top layer removed /// </summary> public PublicKeyEncryptionOnion PeelOne() { if (IsRoot) { throw new Exception( "This object is the root of the onion so there are no more layers to peel. Call 'PeelAll()' instead."); } if (AsymmetricEncryptedKey == null) { throw new Exception( "AsymmetricEncryptedKey not found. Are you sure this onion doesn't have more layers?"); } var rv = InnerOnion.Clone(); // here we want to generate a new object to return since we don't want to decrease the security of the current object using (var aes = new AESCryptoAgent()) using (var rsa = new RSACryptoAgent(AsymmetricThumbprint)) { // decrypt the previously encrypted key var decryptedSymmetricKey = rsa.Decrypt(AsymmetricEncryptedKey); rv.AsymmetricEncryptedKey = aes.Decrypt(SymmetricEncryptedData, decryptedSymmetricKey, SymmetricAlgorithmIV); } return(rv); }
/// <summary> /// Root-level encryption of plain text ctor /// </summary> public PublicKeyEncryptionOnion(byte[] plainData, string asymmetricThumbprint) { if (null == plainData || !plainData.Any()) { throw new ArgumentNullException(nameof(plainData)); } Mandate.That(asymmetricThumbprint, nameof(asymmetricThumbprint)).IsNotNullOrEmpty(); AsymmetricThumbprint = asymmetricThumbprint; InnerOnion = null; using (var aes = new AESCryptoAgent()) using (var rsa = new RSACryptoAgent(asymmetricThumbprint)) { // generate the aes key and use it to encrypt the original plaintext var symmetricKey = aes.GenerateKey(); SymmetricAlgorithmIV = aes.GenerateIV(); SymmetricEncryptedData = aes.Encrypt(plainData, symmetricKey, SymmetricAlgorithmIV); // encrypt the aes key with the public key AsymmetricEncryptedKey = rsa.Encrypt(symmetricKey); } }