Rfc5649WrapEngine
An implementation of the AES Key Wrap with Padding specification as described in RFC 5649.
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
public class Rfc5649WrapEngine : IWrapper
{
private static readonly byte[] DefaultIV = new byte[4] {
166,
89,
89,
166
};
private readonly IBlockCipher m_engine;
private readonly byte[] m_preIV = new byte[4];
private KeyParameter m_key;
private bool m_forWrapping = true;
public virtual string AlgorithmName => m_engine.AlgorithmName;
public Rfc5649WrapEngine(IBlockCipher engine)
{
m_engine = engine;
}
public virtual void Init(bool forWrapping, ICipherParameters parameters)
{
m_forWrapping = forWrapping;
ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom;
if (parametersWithRandom != null)
parameters = parametersWithRandom.Parameters;
KeyParameter keyParameter = parameters as KeyParameter;
if (keyParameter != null) {
m_key = keyParameter;
Array.Copy(DefaultIV, 0, m_preIV, 0, 4);
} else {
ParametersWithIV parametersWithIV = parameters as ParametersWithIV;
if (parametersWithIV != null) {
byte[] iV = parametersWithIV.GetIV();
if (iV.Length != 4)
throw new ArgumentException("IV length not equal to 4", "parameters");
m_key = (KeyParameter)parametersWithIV.Parameters;
Array.Copy(iV, 0, m_preIV, 0, 4);
}
}
}
public virtual byte[] Wrap(byte[] input, int inOff, int length)
{
if (!m_forWrapping)
throw new InvalidOperationException("not set for wrapping");
byte[] array = new byte[8];
Array.Copy(m_preIV, 0, array, 0, 4);
Pack.UInt32_To_BE((uint)length, array, 4);
byte[] array2 = new byte[length];
Array.Copy(input, inOff, array2, 0, length);
byte[] array3 = PadPlaintext(array2);
if (array3.Length == 8) {
byte[] array4 = new byte[array3.Length + array.Length];
Array.Copy(array, 0, array4, 0, array.Length);
Array.Copy(array3, 0, array4, array.Length, array3.Length);
m_engine.Init(true, m_key);
int i = 0;
for (int blockSize = m_engine.GetBlockSize(); i < array4.Length; i += blockSize) {
m_engine.ProcessBlock(array4, i, array4, i);
}
return array4;
}
Rfc3394WrapEngine rfc3394WrapEngine = new Rfc3394WrapEngine(m_engine);
ParametersWithIV parameters = new ParametersWithIV(m_key, array);
rfc3394WrapEngine.Init(true, parameters);
return rfc3394WrapEngine.Wrap(array3, 0, array3.Length);
}
public virtual byte[] Unwrap(byte[] input, int inOff, int length)
{
if (m_forWrapping)
throw new InvalidOperationException("not set for unwrapping");
int num = length / 8;
if (num * 8 != length)
throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
if (num <= 1)
throw new InvalidCipherTextException("unwrap data must be at least 16 bytes");
byte[] array = new byte[length];
Array.Copy(input, inOff, array, 0, length);
byte[] array2 = new byte[length];
byte[] array3 = new byte[8];
byte[] array4;
if (num == 2) {
m_engine.Init(false, m_key);
int i = 0;
for (int blockSize = m_engine.GetBlockSize(); i < array.Length; i += blockSize) {
m_engine.ProcessBlock(array, i, array2, i);
}
Array.Copy(array2, 0, array3, 0, 8);
array4 = new byte[array2.Length - 8];
Array.Copy(array2, 8, array4, 0, array4.Length);
} else {
array2 = Rfc3394UnwrapNoIvCheck(input, inOff, length, array3);
array4 = array2;
}
byte[] array5 = new byte[4];
Array.Copy(array3, 0, array5, 0, 4);
int num2 = (int)Pack.BE_To_UInt32(array3, 4);
bool flag = Arrays.FixedTimeEquals(array5, m_preIV);
int num3 = array4.Length;
int num4 = num3 - 8;
if (num2 <= num4)
flag = false;
if (num2 > num3)
flag = false;
int num5 = num3 - num2;
if (num5 >= 8 || num5 < 0) {
flag = false;
num5 = 4;
}
byte[] b = new byte[num5];
byte[] array6 = new byte[num5];
Array.Copy(array4, array4.Length - num5, array6, 0, num5);
if (!Arrays.FixedTimeEquals(array6, b))
flag = false;
if (!flag)
throw new InvalidCipherTextException("checksum failed");
byte[] array7 = new byte[num2];
Array.Copy(array4, 0, array7, 0, array7.Length);
return array7;
}
private byte[] Rfc3394UnwrapNoIvCheck(byte[] input, int inOff, int inLen, byte[] extractedAIV)
{
byte[] array = new byte[inLen - 8];
byte[] array2 = new byte[16];
Array.Copy(input, inOff, array2, 0, 8);
Array.Copy(input, inOff + 8, array, 0, inLen - 8);
m_engine.Init(false, m_key);
int num = inLen / 8;
num--;
for (int num2 = 5; num2 >= 0; num2--) {
for (int num3 = num; num3 >= 1; num3--) {
Array.Copy(array, 8 * (num3 - 1), array2, 8, 8);
uint num4 = (uint)(num * num2 + num3);
int num5 = 1;
while (num4 != 0) {
array2[8 - num5] ^= (byte)num4;
num4 >>= 8;
num5++;
}
m_engine.ProcessBlock(array2, 0, array2, 0);
Array.Copy(array2, 8, array, 8 * (num3 - 1), 8);
}
}
Array.Copy(array2, 0, extractedAIV, 0, 8);
return array;
}
private static byte[] PadPlaintext(byte[] plaintext)
{
int num = plaintext.Length;
int num2 = (8 - num % 8) % 8;
byte[] array = new byte[num + num2];
Array.Copy(plaintext, 0, array, 0, num);
if (num2 != 0)
Array.Copy(new byte[num2], 0, array, num, num2);
return array;
}
}
}