ISO9796d1Encoding
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
namespace Org.BouncyCastle.Crypto.Encodings
{
public class ISO9796d1Encoding : IAsymmetricBlockCipher
{
private static readonly byte[] Shadows = new byte[16] {
14,
3,
5,
8,
9,
4,
2,
15,
0,
13,
11,
6,
7,
10,
12,
1
};
private static readonly byte[] Inverse = new byte[16] {
8,
15,
6,
1,
5,
2,
11,
12,
3,
4,
13,
10,
14,
9,
0,
7
};
private readonly IAsymmetricBlockCipher m_cipher;
private bool forEncryption;
private int bitSize;
private int padBits;
private BigInteger modulus;
public string AlgorithmName => m_cipher.AlgorithmName + "/ISO9796-1Padding";
public IAsymmetricBlockCipher UnderlyingCipher => m_cipher;
public ISO9796d1Encoding(IAsymmetricBlockCipher cipher)
{
m_cipher = cipher;
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
m_cipher.Init(forEncryption, parameters);
parameters = ParameterUtilities.IgnoreRandom(parameters);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)parameters;
modulus = rsaKeyParameters.Modulus;
bitSize = modulus.BitLength;
this.forEncryption = forEncryption;
}
public int GetInputBlockSize()
{
int inputBlockSize = m_cipher.GetInputBlockSize();
if (forEncryption)
return (inputBlockSize + 1) / 2;
return inputBlockSize;
}
public int GetOutputBlockSize()
{
int outputBlockSize = m_cipher.GetOutputBlockSize();
if (forEncryption)
return outputBlockSize;
return (outputBlockSize + 1) / 2;
}
public void SetPadBits(int padBits)
{
if ((uint)padBits > 7)
throw new ArgumentOutOfRangeException("padBits");
this.padBits = padBits;
}
public int GetPadBits()
{
return padBits;
}
public byte[] ProcessBlock(byte[] input, int inOff, int length)
{
if (!forEncryption)
return DecodeBlock(input, inOff, length);
return EncodeBlock(input, inOff, length);
}
private byte[] EncodeBlock(byte[] input, int inOff, int inLen)
{
byte[] array = new byte[(bitSize + 7) / 8];
int num = padBits + 1;
int num2 = (bitSize + 13) / 16;
for (int i = 0; i < num2; i += inLen) {
if (i > num2 - inLen)
Array.Copy(input, inOff + inLen - (num2 - i), array, array.Length - num2, num2 - i);
else
Array.Copy(input, inOff, array, array.Length - (i + inLen), inLen);
}
for (int j = array.Length - 2 * num2; j != array.Length; j += 2) {
byte b = array[array.Length - num2 + j / 2];
array[j] = (byte)((Shadows[b >> 4] << 4) | Shadows[b & 15]);
array[j + 1] = b;
}
array[array.Length - 2 * inLen] ^= (byte)num;
array[array.Length - 1] = (byte)((array[array.Length - 1] << 4) | 6);
int num3 = 8 - (bitSize - 1) % 8;
int num4 = 0;
if (num3 != 8) {
array[0] &= (byte)(255 >> num3);
array[0] |= (byte)(128 >> num3);
} else {
array[0] = 0;
array[1] |= 128;
num4 = 1;
}
return m_cipher.ProcessBlock(array, num4, array.Length - num4);
}
private byte[] DecodeBlock(byte[] input, int inOff, int inLen)
{
byte[] bytes = m_cipher.ProcessBlock(input, inOff, inLen);
int num = 1;
int num2 = (bitSize + 13) / 16;
BigInteger bigInteger = new BigInteger(1, bytes);
BigInteger bigInteger2;
if ((bigInteger.IntValue & 15) == 6)
bigInteger2 = bigInteger;
else {
bigInteger2 = modulus.Subtract(bigInteger);
if ((bigInteger2.IntValue & 15) != 6)
throw new InvalidCipherTextException("resulting integer iS or (modulus - iS) is not congruent to 6 mod 16");
}
bytes = bigInteger2.ToByteArrayUnsigned();
if ((bytes[bytes.Length - 1] & 15) != 6)
throw new InvalidCipherTextException("invalid forcing byte in block");
bytes[bytes.Length - 1] = (byte)((bytes[bytes.Length - 1] >> 4) | (Inverse[bytes[bytes.Length - 2] >> 4] << 4));
bytes[0] = (byte)((Shadows[bytes[1] >> 4] << 4) | Shadows[bytes[1] & 15]);
bool flag = false;
int num3 = 0;
for (int num4 = bytes.Length - 1; num4 >= bytes.Length - 2 * num2; num4 -= 2) {
int num5 = ((Shadows[bytes[num4] >> 4] << 4) | Shadows[bytes[num4] & 15]) ^ bytes[num4 - 1];
if (num5 != 0) {
if (flag)
throw new InvalidCipherTextException("invalid tsums in block");
flag = true;
num = num5;
num3 = num4 - 1;
}
}
bytes[num3] = 0;
byte[] array = new byte[(bytes.Length - num3) / 2];
for (int i = 0; i < array.Length; i++) {
array[i] = bytes[2 * i + num3 + 1];
}
padBits = num - 1;
return array;
}
}
}