RC2WrapEngine
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 RC2WrapEngine : IWrapper
{
private CbcBlockCipher engine;
private ICipherParameters parameters;
private ParametersWithIV paramPlusIV;
private byte[] iv;
private bool forWrapping;
private SecureRandom sr;
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 => "RC2";
public virtual void Init(bool forWrapping, ICipherParameters parameters)
{
this.forWrapping = forWrapping;
engine = new CbcBlockCipher(new RC2Engine());
ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom;
if (parametersWithRandom != null) {
sr = parametersWithRandom.Random;
parameters = parametersWithRandom.Parameters;
} else
sr = (forWrapping ? CryptoServicesRegistrar.GetSecureRandom() : null);
if (parameters is ParametersWithIV) {
if (!forWrapping)
throw new ArgumentException("You should not supply an IV for unwrapping");
paramPlusIV = (ParametersWithIV)parameters;
iv = paramPlusIV.GetIV();
this.parameters = paramPlusIV.Parameters;
if (iv.Length != 8)
throw new ArgumentException("IV is not 8 octets");
} else {
this.parameters = parameters;
if (this.forWrapping) {
iv = new byte[8];
sr.NextBytes(iv);
paramPlusIV = new ParametersWithIV(this.parameters, iv);
}
}
}
public virtual byte[] Wrap(byte[] input, int inOff, int length)
{
if (!forWrapping)
throw new InvalidOperationException("Not initialized for wrapping");
int num = (length + 8) & -8;
int num2 = iv.Length;
byte[] array = Arrays.CopyOf(iv, num2 + num + 8);
array[num2] = (byte)length;
Array.Copy(input, inOff, array, num2 + 1, length);
int num3 = num - length - 1;
if (num3 > 0)
sr.NextBytes(array, num2 + num - num3, num3);
CalculateCmsKeyChecksum(array, num2, num, array, num2 + num);
int blockSize = engine.GetBlockSize();
engine.Init(true, paramPlusIV);
int i;
for (i = num2; i < array.Length; i += blockSize) {
engine.ProcessBlock(array, i, array, i);
}
if (i != array.Length)
throw new InvalidOperationException("Not multiple of block length");
Array.Reverse((Array)array);
engine.Init(true, new ParametersWithIV(parameters, IV2));
int j;
for (j = 0; j < array.Length; j += blockSize) {
engine.ProcessBlock(array, j, array, j);
}
if (j != array.Length)
throw new InvalidOperationException("Not multiple of block length");
return array;
}
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");
if (length % engine.GetBlockSize() != 0)
throw new InvalidCipherTextException("Ciphertext not multiple of " + engine.GetBlockSize().ToString());
int blockSize = engine.GetBlockSize();
byte[] array = new byte[length];
engine.Init(false, new ParametersWithIV(parameters, IV2));
int i;
for (i = 0; i < array.Length; i += blockSize) {
engine.ProcessBlock(input, inOff + i, array, i);
}
if (i != array.Length)
throw new InvalidOperationException("Not multiple of block length");
Array.Reverse((Array)array);
iv = Arrays.CopyOf(array, 8);
paramPlusIV = new ParametersWithIV(parameters, iv);
engine.Init(false, paramPlusIV);
int j;
for (j = 8; j < array.Length; j += blockSize) {
engine.ProcessBlock(array, j, array, j);
}
if (j != array.Length)
throw new InvalidOperationException("Not multiple of block length");
if (!CheckCmsKeyChecksum(array, 8, array.Length - 16, array, array.Length - 8))
throw new InvalidCipherTextException("Checksum inside ciphertext is corrupted");
int num = array.Length - 16 - array[8] - 1;
if ((num & 7) != num)
throw new InvalidCipherTextException("Invalid padding length (" + num.ToString() + ")");
return Arrays.CopyOfRange(array, 9, 9 + array[8]);
}
private void CalculateCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
{
sha1.BlockUpdate(key, keyOff, keyLen);
sha1.DoFinal(digest, 0);
Array.Copy(digest, 0, cks, cksOff, 8);
}
private bool CheckCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
{
sha1.BlockUpdate(key, keyOff, keyLen);
sha1.DoFinal(digest, 0);
return Arrays.FixedTimeEquals(8, digest, 0, cks, cksOff);
}
}
}