DesEdeWrapEngine
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
public class DesEdeWrapEngine : IWrapper
{
private CbcBlockCipher engine;
private KeyParameter param;
private ParametersWithIV paramPlusIV;
private byte[] iv;
private bool forWrapping;
private static readonly byte[] IV2 = new byte[8] {
74,
221,
162,
44,
121,
232,
33,
5
};
private readonly IDigest sha1 = new Sha1Digest();
private readonly byte[] digest = new byte[20];
public virtual string AlgorithmName => "DESede";
public virtual void Init(bool forWrapping, ICipherParameters parameters)
{
this.forWrapping = forWrapping;
engine = new CbcBlockCipher(new DesEdeEngine());
SecureRandom secureRandom = null;
ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom;
if (parametersWithRandom != null) {
parameters = parametersWithRandom.Parameters;
secureRandom = parametersWithRandom.Random;
}
KeyParameter keyParameter = parameters as KeyParameter;
if (keyParameter != null) {
param = keyParameter;
if (this.forWrapping) {
iv = new byte[8];
CryptoServicesRegistrar.GetSecureRandom(secureRandom).NextBytes(iv);
paramPlusIV = new ParametersWithIV(param, iv);
}
} else {
ParametersWithIV parametersWithIV = parameters as ParametersWithIV;
if (parametersWithIV != null) {
if (!forWrapping)
throw new ArgumentException("You should not supply an IV for unwrapping");
paramPlusIV = parametersWithIV;
iv = parametersWithIV.GetIV();
param = (KeyParameter)parametersWithIV.Parameters;
if (iv.Length != 8)
throw new ArgumentException("IV is not 8 octets", "parameters");
}
}
}
public virtual byte[] Wrap(byte[] input, int inOff, int length)
{
if (!forWrapping)
throw new InvalidOperationException("Not initialized for wrapping");
byte[] array = new byte[length];
Array.Copy(input, inOff, array, 0, length);
byte[] array2 = CalculateCmsKeyChecksum(array);
byte[] array3 = new byte[array.Length + array2.Length];
Array.Copy(array, 0, array3, 0, array.Length);
Array.Copy(array2, 0, array3, array.Length, array2.Length);
int blockSize = engine.GetBlockSize();
if (array3.Length % blockSize != 0)
throw new InvalidOperationException("Not multiple of block length");
engine.Init(true, paramPlusIV);
byte[] array4 = new byte[array3.Length];
for (int i = 0; i != array3.Length; i += blockSize) {
engine.ProcessBlock(array3, i, array4, i);
}
byte[] array5 = new byte[iv.Length + array4.Length];
Array.Copy(iv, 0, array5, 0, iv.Length);
Array.Copy(array4, 0, array5, iv.Length, array4.Length);
Array.Reverse(array5);
ParametersWithIV parameters = new ParametersWithIV(param, IV2);
engine.Init(true, parameters);
for (int j = 0; j != array5.Length; j += blockSize) {
engine.ProcessBlock(array5, j, array5, j);
}
return array5;
}
public virtual byte[] Unwrap(byte[] input, int inOff, int length)
{
if (forWrapping)
throw new InvalidOperationException("Not set for unwrapping");
if (input == null)
throw new InvalidCipherTextException("Null pointer as ciphertext");
int blockSize = engine.GetBlockSize();
if (length % blockSize != 0)
throw new InvalidCipherTextException("Ciphertext not multiple of " + blockSize.ToString());
ParametersWithIV parameters = new ParametersWithIV(param, IV2);
engine.Init(false, parameters);
byte[] array = new byte[length];
for (int i = 0; i != array.Length; i += blockSize) {
engine.ProcessBlock(input, inOff + i, array, i);
}
Array.Reverse(array);
iv = new byte[8];
byte[] array2 = new byte[array.Length - 8];
Array.Copy(array, 0, iv, 0, 8);
Array.Copy(array, 8, array2, 0, array.Length - 8);
paramPlusIV = new ParametersWithIV(param, iv);
engine.Init(false, paramPlusIV);
byte[] array3 = new byte[array2.Length];
for (int j = 0; j != array3.Length; j += blockSize) {
engine.ProcessBlock(array2, j, array3, j);
}
byte[] array4 = new byte[array3.Length - 8];
byte[] array5 = new byte[8];
Array.Copy(array3, 0, array4, 0, array3.Length - 8);
Array.Copy(array3, array3.Length - 8, array5, 0, 8);
if (!CheckCmsKeyChecksum(array4, array5))
throw new InvalidCipherTextException("Checksum inside ciphertext is corrupted");
return array4;
}
private byte[] CalculateCmsKeyChecksum(byte[] key)
{
sha1.BlockUpdate(key, 0, key.Length);
sha1.DoFinal(digest, 0);
byte[] array = new byte[8];
Array.Copy(digest, 0, array, 0, 8);
return array;
}
private bool CheckCmsKeyChecksum(byte[] key, byte[] checksum)
{
return Arrays.FixedTimeEquals(CalculateCmsKeyChecksum(key), checksum);
}
}
}