diff --git a/crypto/src/crypto/IBlockCipher.cs b/crypto/src/crypto/IBlockCipher.cs
index a3ad6d6e5..b26aaa49f 100644
--- a/crypto/src/crypto/IBlockCipher.cs
+++ b/crypto/src/crypto/IBlockCipher.cs
@@ -28,9 +28,19 @@ namespace Org.BouncyCastle.Crypto
/// <returns>The number of bytes processed and produced.</returns>
int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff);
- /// <summary>
- /// Reset the cipher to the same state as it was after the last init (if there was one).
- /// </summary>
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+
+ /// <summary>Process a block.</summary>
+ /// <param name="input">The input block as a span.</param>
+ /// <param name="output">The output span.</param>
+ /// <exception cref="DataLengthException">If input block is wrong size, or output span too small.</exception>
+ /// <returns>The number of bytes processed and produced.</returns>
+ int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output);
+#endif
+
+ /// <summary>
+ /// Reset the cipher to the same state as it was after the last init (if there was one).
+ /// </summary>
void Reset();
}
}
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 10c720968..21daf06d8 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -486,6 +486,16 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, 16, "input buffer too short");
Check.OutputLength(output, outOff, 16, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (forEncryption)
+ {
+ EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff), WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff), WorkingKey);
+ }
+#else
if (forEncryption)
{
EncryptBlock(input, inOff, output, outOff, WorkingKey);
@@ -494,14 +504,134 @@ namespace Org.BouncyCastle.Crypto.Engines
{
DecryptBlock(input, inOff, output, outOff, WorkingKey);
}
+#endif
return BLOCK_SIZE;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (WorkingKey == null)
+ throw new InvalidOperationException("AES engine not initialised");
+
+ Check.DataLength(input, 16, "input buffer too short");
+ Check.OutputLength(output, 16, "output buffer too short");
+
+ if (forEncryption)
+ {
+ EncryptBlock(input, output, WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(input, output, WorkingKey);
+ }
+
+ return BLOCK_SIZE;
+ }
+#endif
+
public virtual void Reset()
{
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
+ {
+ uint C0 = Pack.LE_To_UInt32(input);
+ uint C1 = Pack.LE_To_UInt32(input[4..]);
+ uint C2 = Pack.LE_To_UInt32(input[8..]);
+ uint C3 = Pack.LE_To_UInt32(input[12..]);
+
+ uint[] kw = KW[0];
+ uint t0 = C0 ^ kw[0];
+ uint t1 = C1 ^ kw[1];
+ uint t2 = C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = C3 ^ kw[3];
+ int r = 1;
+ while (r < ROUNDS - 1)
+ {
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+ r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
+ r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
+ r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
+ kw = KW[r++];
+ t0 = T0[r0 & 255] ^ Shift(T0[(r1 >> 8) & 255], 24) ^ Shift(T0[(r2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+ t1 = T0[r1 & 255] ^ Shift(T0[(r2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(r0 >> 24) & 255], 8) ^ kw[1];
+ t2 = T0[r2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(r0 >> 16) & 255], 16) ^ Shift(T0[(r1 >> 24) & 255], 8) ^ kw[2];
+ r3 = T0[r3 & 255] ^ Shift(T0[(r0 >> 8) & 255], 24) ^ Shift(T0[(r1 >> 16) & 255], 16) ^ Shift(T0[(r2 >> 24) & 255], 8) ^ kw[3];
+ }
+
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+ r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
+ r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
+ r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
+
+ // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+ kw = KW[r];
+ C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[0];
+ C1 = (uint)s[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[1];
+ C2 = (uint)s[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
+ C3 = (uint)s[r3 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
+
+ Pack.UInt32_To_LE(C0, output);
+ Pack.UInt32_To_LE(C1, output[4..]);
+ Pack.UInt32_To_LE(C2, output[8..]);
+ Pack.UInt32_To_LE(C3, output[12..]);
+ }
+
+ private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
+ {
+ uint C0 = Pack.LE_To_UInt32(input);
+ uint C1 = Pack.LE_To_UInt32(input[4..]);
+ uint C2 = Pack.LE_To_UInt32(input[8..]);
+ uint C3 = Pack.LE_To_UInt32(input[12..]);
+
+ uint[] kw = KW[ROUNDS];
+ uint t0 = C0 ^ kw[0];
+ uint t1 = C1 ^ kw[1];
+ uint t2 = C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = C3 ^ kw[3];
+ int r = ROUNDS - 1;
+ while (r > 1)
+ {
+ kw = KW[r--];
+ r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
+ kw = KW[r--];
+ t0 = Tinv0[r0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(r2 >> 16) & 255], 16) ^ Shift(Tinv0[(r1 >> 24) & 255], 8) ^ kw[0];
+ t1 = Tinv0[r1 & 255] ^ Shift(Tinv0[(r0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(r2 >> 24) & 255], 8) ^ kw[1];
+ t2 = Tinv0[r2 & 255] ^ Shift(Tinv0[(r1 >> 8) & 255], 24) ^ Shift(Tinv0[(r0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(r2 >> 8) & 255], 24) ^ Shift(Tinv0[(r1 >> 16) & 255], 16) ^ Shift(Tinv0[(r0 >> 24) & 255], 8) ^ kw[3];
+ }
+
+ kw = KW[1];
+ r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
+
+ // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+ kw = KW[0];
+ C0 = (uint)Si[r0 & 255] ^ (((uint)s[(r3 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
+ C1 = (uint)s[r1 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r2 >> 24) & 255]) << 24) ^ kw[1];
+ C2 = (uint)s[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[2];
+ C3 = (uint)Si[r3 & 255] ^ (((uint)s[(r2 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[3];
+
+ Pack.UInt32_To_LE(C0, output);
+ Pack.UInt32_To_LE(C1, output[4..]);
+ Pack.UInt32_To_LE(C2, output[8..]);
+ Pack.UInt32_To_LE(C3, output[12..]);
+ }
+#else
private void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff, uint[][] KW)
{
uint C0 = Pack.LE_To_UInt32(input, inOff + 0);
@@ -597,5 +727,6 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_LE(C2, output, outOff + 8);
Pack.UInt32_To_LE(C3, output, outOff + 12);
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index 8d5a98a9f..f34901fac 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -380,6 +380,16 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, 16, "input buffer too short");
Check.OutputLength(output, outOff, 16, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (forEncryption)
+ {
+ EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff), WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff), WorkingKey);
+ }
+#else
if (forEncryption)
{
EncryptBlock(input, inOff, output, outOff, WorkingKey);
@@ -388,14 +398,134 @@ namespace Org.BouncyCastle.Crypto.Engines
{
DecryptBlock(input, inOff, output, outOff, WorkingKey);
}
+#endif
return BLOCK_SIZE;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (WorkingKey == null)
+ throw new InvalidOperationException("AES engine not initialised");
+
+ Check.DataLength(input, 16, "input buffer too short");
+ Check.OutputLength(output, 16, "output buffer too short");
+
+ if (forEncryption)
+ {
+ EncryptBlock(input, output, WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(input, output, WorkingKey);
+ }
+
+ return BLOCK_SIZE;
+ }
+#endif
+
public virtual void Reset()
{
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
+ {
+ uint C0 = Pack.LE_To_UInt32(input);
+ uint C1 = Pack.LE_To_UInt32(input[4..]);
+ uint C2 = Pack.LE_To_UInt32(input[8..]);
+ uint C3 = Pack.LE_To_UInt32(input[12..]);
+
+ uint[] kw = KW[0];
+ uint t0 = C0 ^ kw[0];
+ uint t1 = C1 ^ kw[1];
+ uint t2 = C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = C3 ^ kw[3];
+ int r = 1;
+ while (r < ROUNDS - 1)
+ {
+ kw = KW[r++];
+ r0 = Mcol((uint)S[t0 & 255] ^ (((uint)S[(t1 >> 8) & 255]) << 8) ^ (((uint)S[(t2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+ r1 = Mcol((uint)S[t1 & 255] ^ (((uint)S[(t2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(t0 >> 24) & 255]) << 24)) ^ kw[1];
+ r2 = Mcol((uint)S[t2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(t0 >> 16) & 255]) << 16) ^ (((uint)S[(t1 >> 24) & 255]) << 24)) ^ kw[2];
+ r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(t0 >> 8) & 255]) << 8) ^ (((uint)S[(t1 >> 16) & 255]) << 16) ^ (((uint)S[(t2 >> 24) & 255]) << 24)) ^ kw[3];
+ kw = KW[r++];
+ t0 = Mcol((uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+ t1 = Mcol((uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24)) ^ kw[1];
+ t2 = Mcol((uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24)) ^ kw[2];
+ r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24)) ^ kw[3];
+ }
+
+ kw = KW[r++];
+ r0 = Mcol((uint)S[t0 & 255] ^ (((uint)S[(t1 >> 8) & 255]) << 8) ^ (((uint)S[(t2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+ r1 = Mcol((uint)S[t1 & 255] ^ (((uint)S[(t2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(t0 >> 24) & 255]) << 24)) ^ kw[1];
+ r2 = Mcol((uint)S[t2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(t0 >> 16) & 255]) << 16) ^ (((uint)S[(t1 >> 24) & 255]) << 24)) ^ kw[2];
+ r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(t0 >> 8) & 255]) << 8) ^ (((uint)S[(t1 >> 16) & 255]) << 16) ^ (((uint)S[(t2 >> 24) & 255]) << 24)) ^ kw[3];
+
+ // the final round is a simple function of S
+
+ kw = KW[r];
+ C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
+ C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
+ C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
+ C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
+
+ Pack.UInt32_To_LE(C0, output);
+ Pack.UInt32_To_LE(C1, output[4..]);
+ Pack.UInt32_To_LE(C2, output[8..]);
+ Pack.UInt32_To_LE(C3, output[12..]);
+ }
+
+ private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
+ {
+ uint C0 = Pack.LE_To_UInt32(input);
+ uint C1 = Pack.LE_To_UInt32(input[4..]);
+ uint C2 = Pack.LE_To_UInt32(input[8..]);
+ uint C3 = Pack.LE_To_UInt32(input[12..]);
+
+ uint[] kw = KW[ROUNDS];
+ uint t0 = C0 ^ kw[0];
+ uint t1 = C1 ^ kw[1];
+ uint t2 = C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = C3 ^ kw[3];
+ int r = ROUNDS - 1;
+ while (r > 1)
+ {
+ kw = KW[r--];
+ r0 = Inv_Mcol((uint)Si[t0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(t2 >> 16) & 255]) << 16) ^ ((uint)Si[(t1 >> 24) & 255] << 24)) ^ kw[0];
+ r1 = Inv_Mcol((uint)Si[t1 & 255] ^ (((uint)Si[(t0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(t2 >> 24) & 255] << 24)) ^ kw[1];
+ r2 = Inv_Mcol((uint)Si[t2 & 255] ^ (((uint)Si[(t1 >> 8) & 255]) << 8) ^ (((uint)Si[(t0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+ r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(t2 >> 8) & 255]) << 8) ^ (((uint)Si[(t1 >> 16) & 255]) << 16) ^ ((uint)Si[(t0 >> 24) & 255] << 24)) ^ kw[3];
+ kw = KW[r--];
+ t0 = Inv_Mcol((uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ ((uint)Si[(r1 >> 24) & 255] << 24)) ^ kw[0];
+ t1 = Inv_Mcol((uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(r2 >> 24) & 255] << 24)) ^ kw[1];
+ t2 = Inv_Mcol((uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+ r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ ((uint)Si[(r0 >> 24) & 255] << 24)) ^ kw[3];
+ }
+
+ kw = KW[1];
+ r0 = Inv_Mcol((uint)Si[t0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(t2 >> 16) & 255]) << 16) ^ ((uint)Si[(t1 >> 24) & 255] << 24)) ^ kw[0];
+ r1 = Inv_Mcol((uint)Si[t1 & 255] ^ (((uint)Si[(t0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(t2 >> 24) & 255] << 24)) ^ kw[1];
+ r2 = Inv_Mcol((uint)Si[t2 & 255] ^ (((uint)Si[(t1 >> 8) & 255]) << 8) ^ (((uint)Si[(t0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+ r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(t2 >> 8) & 255]) << 8) ^ (((uint)Si[(t1 >> 16) & 255]) << 16) ^ ((uint)Si[(t0 >> 24) & 255] << 24)) ^ kw[3];
+
+ // the final round's table is a simple function of Si
+
+ kw = KW[0];
+ C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
+ C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
+ C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
+ C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
+
+ Pack.UInt32_To_LE(C0, output);
+ Pack.UInt32_To_LE(C1, output[4..]);
+ Pack.UInt32_To_LE(C2, output[8..]);
+ Pack.UInt32_To_LE(C3, output[12..]);
+ }
+#else
private void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff, uint[][] KW)
{
uint C0 = Pack.LE_To_UInt32(input, inOff + 0);
@@ -491,5 +621,6 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_LE(C2, output, outOff + 8);
Pack.UInt32_To_LE(C3, output, outOff + 12);
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/AriaEngine.cs b/crypto/src/crypto/engines/AriaEngine.cs
index 2f94dc048..75af84320 100644
--- a/crypto/src/crypto/engines/AriaEngine.cs
+++ b/crypto/src/crypto/engines/AriaEngine.cs
@@ -195,6 +195,36 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (m_roundKeys == null)
+ throw new InvalidOperationException("ARIA engine not initialised");
+
+ Check.DataLength(input, BlockSize, "input buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
+
+ byte[] z = new byte[BlockSize];
+ input[..BlockSize].CopyTo(z);
+
+ int i = 0, rounds = m_roundKeys.Length - 3;
+ while (i < rounds)
+ {
+ FO(z, m_roundKeys[i++]);
+ FE(z, m_roundKeys[i++]);
+ }
+
+ FO(z, m_roundKeys[i++]);
+ Xor(z, m_roundKeys[i++]);
+ SL2(z);
+ Xor(z, m_roundKeys[i]);
+
+ z.CopyTo(output);
+
+ return BlockSize;
+ }
+#endif
+
public virtual void Reset()
{
// Empty
diff --git a/crypto/src/crypto/engines/BlowfishEngine.cs b/crypto/src/crypto/engines/BlowfishEngine.cs
index 1b3dd9743..aa323581a 100644
--- a/crypto/src/crypto/engines/BlowfishEngine.cs
+++ b/crypto/src/crypto/engines/BlowfishEngine.cs
@@ -347,11 +347,7 @@ namespace Org.BouncyCastle.Crypto.Engines
get { return false; }
}
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("Blowfish not initialised");
@@ -359,7 +355,17 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
- if (encrypting)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (encrypting)
+ {
+ EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
+ if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
@@ -367,11 +373,34 @@ namespace Org.BouncyCastle.Crypto.Engines
{
DecryptBlock(input, inOff, output, outOff);
}
+#endif
return BLOCK_SIZE;
}
- public void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Blowfish not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, output);
+ }
+ else
+ {
+ DecryptBlock(input, output);
+ }
+
+ return BLOCK_SIZE;
+ }
+#endif
+
+ public void Reset()
{
}
@@ -499,16 +528,46 @@ namespace Org.BouncyCastle.Crypto.Engines
ProcessTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
}
- /**
- * Encrypt the given input starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- * The input will be an exact multiple of our blocksize.
- */
- private void EncryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint xl = Pack.BE_To_UInt32(input);
+ uint xr = Pack.BE_To_UInt32(input[4..]);
+
+ xl ^= P[0];
+
+ for (int i = 1; i < ROUNDS; i += 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i + 1];
+ }
+
+ xr ^= P[ROUNDS + 1];
+
+ Pack.UInt32_To_BE(xr, output);
+ Pack.UInt32_To_BE(xl, output[4..]);
+ }
+
+ private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint xl = Pack.BE_To_UInt32(input);
+ uint xr = Pack.BE_To_UInt32(input[4..]);
+
+ xl ^= P[ROUNDS + 1];
+
+ for (int i = ROUNDS; i > 0; i -= 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i - 1];
+ }
+
+ xr ^= P[0];
+
+ Pack.UInt32_To_BE(xr, output);
+ Pack.UInt32_To_BE(xl, output[4..]);
+ }
+#else
+ private void EncryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
uint xl = Pack.BE_To_UInt32(src, srcIndex);
uint xr = Pack.BE_To_UInt32(src, srcIndex+4);
@@ -527,16 +586,7 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_BE(xl, dst, dstIndex + 4);
}
- /**
- * Decrypt the given input starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- * The input will be an exact multiple of our blocksize.
- */
- private void DecryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+ private void DecryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
uint xl = Pack.BE_To_UInt32(src, srcIndex);
uint xr = Pack.BE_To_UInt32(src, srcIndex + 4);
@@ -554,5 +604,6 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_BE(xr, dst, dstIndex);
Pack.UInt32_To_BE(xl, dst, dstIndex + 4);
}
- }
+#endif
+ }
}
diff --git a/crypto/src/crypto/engines/CamelliaEngine.cs b/crypto/src/crypto/engines/CamelliaEngine.cs
index 2222e4b7c..512448a27 100644
--- a/crypto/src/crypto/engines/CamelliaEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -275,25 +276,6 @@ namespace Org.BouncyCastle.Crypto.Engines
ki[3 + ioff] = ko[1 + ooff];
}
- private static uint bytes2uint(byte[] src, int offset)
- {
- uint word = 0;
- for (int i = 0; i < 4; i++)
- {
- word = (word << 8) + (uint)src[i + offset];
- }
- return word;
- }
-
- private static void uint2bytes(uint word, byte[] dst, int offset)
- {
- for (int i = 0; i < 4; i++)
- {
- dst[(3 - i) + offset] = (byte)word;
- word >>= 8;
- }
- }
-
private static void camelliaF2(uint[] s, uint[] skey, int keyoff)
{
uint t1, t2, u, v;
@@ -346,38 +328,23 @@ namespace Org.BouncyCastle.Crypto.Engines
switch (key.Length)
{
- case 16:
- _keyIs128 = true;
- k[0] = bytes2uint(key, 0);
- k[1] = bytes2uint(key, 4);
- k[2] = bytes2uint(key, 8);
- k[3] = bytes2uint(key, 12);
- k[4] = k[5] = k[6] = k[7] = 0;
- break;
- case 24:
- k[0] = bytes2uint(key, 0);
- k[1] = bytes2uint(key, 4);
- k[2] = bytes2uint(key, 8);
- k[3] = bytes2uint(key, 12);
- k[4] = bytes2uint(key, 16);
- k[5] = bytes2uint(key, 20);
- k[6] = ~k[4];
- k[7] = ~k[5];
- _keyIs128 = false;
- break;
- case 32:
- k[0] = bytes2uint(key, 0);
- k[1] = bytes2uint(key, 4);
- k[2] = bytes2uint(key, 8);
- k[3] = bytes2uint(key, 12);
- k[4] = bytes2uint(key, 16);
- k[5] = bytes2uint(key, 20);
- k[6] = bytes2uint(key, 24);
- k[7] = bytes2uint(key, 28);
- _keyIs128 = false;
- break;
- default:
- throw new ArgumentException("key sizes are only 16/24/32 bytes.");
+ case 16:
+ _keyIs128 = true;
+ Pack.BE_To_UInt32(key, 0, k, 0, 4);
+ k[4] = k[5] = k[6] = k[7] = 0;
+ break;
+ case 24:
+ Pack.BE_To_UInt32(key, 0, k, 0, 6);
+ k[6] = ~k[4];
+ k[7] = ~k[5];
+ _keyIs128 = false;
+ break;
+ case 32:
+ Pack.BE_To_UInt32(key, 0, k, 0, 8);
+ _keyIs128 = false;
+ break;
+ default:
+ throw new ArgumentException("key sizes are only 16/24/32 bytes.");
}
for (int i = 0; i < 4; i++)
@@ -537,13 +504,78 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int ProcessBlock128(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint[] state = new uint[4];
+ Pack.BE_To_UInt32(input, state);
+
+ state[0] ^= kw[0];
+ state[1] ^= kw[1];
+ state[2] ^= kw[2];
+ state[3] ^= kw[3];
+
+ camelliaF2(state, subkey, 0);
+ camelliaF2(state, subkey, 4);
+ camelliaF2(state, subkey, 8);
+ camelliaFLs(state, ke, 0);
+ camelliaF2(state, subkey, 12);
+ camelliaF2(state, subkey, 16);
+ camelliaF2(state, subkey, 20);
+ camelliaFLs(state, ke, 4);
+ camelliaF2(state, subkey, 24);
+ camelliaF2(state, subkey, 28);
+ camelliaF2(state, subkey, 32);
+
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output[4..]);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output[8..]);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output[12..]);
+
+ return BLOCK_SIZE;
+ }
+
+ private int ProcessBlock192or256(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint[] state = new uint[4];
+ Pack.BE_To_UInt32(input, state);
+
+ state[0] ^= kw[0];
+ state[1] ^= kw[1];
+ state[2] ^= kw[2];
+ state[3] ^= kw[3];
+
+ camelliaF2(state, subkey, 0);
+ camelliaF2(state, subkey, 4);
+ camelliaF2(state, subkey, 8);
+ camelliaFLs(state, ke, 0);
+ camelliaF2(state, subkey, 12);
+ camelliaF2(state, subkey, 16);
+ camelliaF2(state, subkey, 20);
+ camelliaFLs(state, ke, 4);
+ camelliaF2(state, subkey, 24);
+ camelliaF2(state, subkey, 28);
+ camelliaF2(state, subkey, 32);
+ camelliaFLs(state, ke, 8);
+ camelliaF2(state, subkey, 36);
+ camelliaF2(state, subkey, 40);
+ camelliaF2(state, subkey, 44);
+
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output[4..]);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output[8..]);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output[12..]);
+
+ return BLOCK_SIZE;
+ }
+#else
+ private int ProcessBlock128(byte[] input, int inOff, byte[] output, int outOff)
{
uint[] state = new uint[4];
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
+ state[i] = Pack.BE_To_UInt32(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -558,26 +590,21 @@ namespace Org.BouncyCastle.Crypto.Engines
camelliaF2(state, subkey, 28);
camelliaF2(state, subkey, 32);
- state[2] ^= kw[4];
- state[3] ^= kw[5];
- state[0] ^= kw[6];
- state[1] ^= kw[7];
-
- uint2bytes(state[2], output, outOff);
- uint2bytes(state[3], output, outOff + 4);
- uint2bytes(state[0], output, outOff + 8);
- uint2bytes(state[1], output, outOff + 12);
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output, outOff);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output, outOff + 4);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output, outOff + 8);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output, outOff + 12);
return BLOCK_SIZE;
}
- private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
+ private int ProcessBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
{
uint[] state = new uint[4];
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
+ state[i] = Pack.BE_To_UInt32(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -596,18 +623,14 @@ namespace Org.BouncyCastle.Crypto.Engines
camelliaF2(state, subkey, 40);
camelliaF2(state, subkey, 44);
- state[2] ^= kw[4];
- state[3] ^= kw[5];
- state[0] ^= kw[6];
- state[1] ^= kw[7];
-
- uint2bytes(state[2], output, outOff);
- uint2bytes(state[3], output, outOff + 4);
- uint2bytes(state[0], output, outOff + 8);
- uint2bytes(state[1], output, outOff + 12);
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output, outOff);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output, outOff + 4);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output, outOff + 8);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output, outOff + 12);
return BLOCK_SIZE;
}
+#endif
public CamelliaEngine()
{
@@ -640,11 +663,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (!initialised)
throw new InvalidOperationException("Camellia engine not initialised");
@@ -652,17 +671,48 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
- if (_keyIs128)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (_keyIs128)
+ {
+ return ProcessBlock128(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ return ProcessBlock192or256(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
+ if (_keyIs128)
+ {
+ return ProcessBlock128(input, inOff, output, outOff);
+ }
+ else
+ {
+ return ProcessBlock192or256(input, inOff, output, outOff);
+ }
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Camellia engine not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ if (_keyIs128)
{
- return processBlock128(input, inOff, output, outOff);
+ return ProcessBlock128(input, output);
}
else
{
- return processBlock192or256(input, inOff, output, outOff);
+ return ProcessBlock192or256(input, output);
}
}
+#endif
- public virtual void Reset()
+ public virtual void Reset()
{
// nothing
}
diff --git a/crypto/src/crypto/engines/CamelliaLightEngine.cs b/crypto/src/crypto/engines/CamelliaLightEngine.cs
index daf0316e2..03611f137 100644
--- a/crypto/src/crypto/engines/CamelliaLightEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaLightEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -158,25 +159,6 @@ namespace Org.BouncyCastle.Crypto.Engines
ki[3 + ioff] = ko[1 + ooff];
}
- private static uint bytes2uint(byte[] src, int offset)
- {
- uint word = 0;
- for (int i = 0; i < 4; i++)
- {
- word = (word << 8) + (uint)src[i + offset];
- }
- return word;
- }
-
- private static void uint2bytes(uint word, byte[] dst, int offset)
- {
- for (int i = 0; i < 4; i++)
- {
- dst[(3 - i) + offset] = (byte)word;
- word >>= 8;
- }
- }
-
private byte lRot8(byte v, int rot)
{
return (byte)(((uint)v << rot) | ((uint)v >> (8 - rot)));
@@ -258,38 +240,23 @@ namespace Org.BouncyCastle.Crypto.Engines
switch (key.Length)
{
- case 16:
- _keyis128 = true;
- k[0] = bytes2uint(key, 0);
- k[1] = bytes2uint(key, 4);
- k[2] = bytes2uint(key, 8);
- k[3] = bytes2uint(key, 12);
- k[4] = k[5] = k[6] = k[7] = 0;
- break;
- case 24:
- k[0] = bytes2uint(key, 0);
- k[1] = bytes2uint(key, 4);
- k[2] = bytes2uint(key, 8);
- k[3] = bytes2uint(key, 12);
- k[4] = bytes2uint(key, 16);
- k[5] = bytes2uint(key, 20);
- k[6] = ~k[4];
- k[7] = ~k[5];
- _keyis128 = false;
- break;
- case 32:
- k[0] = bytes2uint(key, 0);
- k[1] = bytes2uint(key, 4);
- k[2] = bytes2uint(key, 8);
- k[3] = bytes2uint(key, 12);
- k[4] = bytes2uint(key, 16);
- k[5] = bytes2uint(key, 20);
- k[6] = bytes2uint(key, 24);
- k[7] = bytes2uint(key, 28);
- _keyis128 = false;
- break;
- default:
- throw new ArgumentException("key sizes are only 16/24/32 bytes.");
+ case 16:
+ _keyis128 = true;
+ Pack.BE_To_UInt32(key, 0, k, 0, 4);
+ k[4] = k[5] = k[6] = k[7] = 0;
+ break;
+ case 24:
+ Pack.BE_To_UInt32(key, 0, k, 0, 6);
+ k[6] = ~k[4];
+ k[7] = ~k[5];
+ _keyis128 = false;
+ break;
+ case 32:
+ Pack.BE_To_UInt32(key, 0, k, 0, 8);
+ _keyis128 = false;
+ break;
+ default:
+ throw new ArgumentException("key sizes are only 16/24/32 bytes.");
}
for (int i = 0; i < 4; i++)
@@ -449,13 +416,78 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int ProcessBlock128(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint[] state = new uint[4];
+ Pack.BE_To_UInt32(input, state);
+
+ state[0] ^= kw[0];
+ state[1] ^= kw[1];
+ state[2] ^= kw[2];
+ state[3] ^= kw[3];
+
+ camelliaF2(state, subkey, 0);
+ camelliaF2(state, subkey, 4);
+ camelliaF2(state, subkey, 8);
+ camelliaFLs(state, ke, 0);
+ camelliaF2(state, subkey, 12);
+ camelliaF2(state, subkey, 16);
+ camelliaF2(state, subkey, 20);
+ camelliaFLs(state, ke, 4);
+ camelliaF2(state, subkey, 24);
+ camelliaF2(state, subkey, 28);
+ camelliaF2(state, subkey, 32);
+
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output[4..]);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output[8..]);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output[12..]);
+
+ return BLOCK_SIZE;
+ }
+
+ private int ProcessBlock192or256(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint[] state = new uint[4];
+ Pack.BE_To_UInt32(input, state);
+
+ state[0] ^= kw[0];
+ state[1] ^= kw[1];
+ state[2] ^= kw[2];
+ state[3] ^= kw[3];
+
+ camelliaF2(state, subkey, 0);
+ camelliaF2(state, subkey, 4);
+ camelliaF2(state, subkey, 8);
+ camelliaFLs(state, ke, 0);
+ camelliaF2(state, subkey, 12);
+ camelliaF2(state, subkey, 16);
+ camelliaF2(state, subkey, 20);
+ camelliaFLs(state, ke, 4);
+ camelliaF2(state, subkey, 24);
+ camelliaF2(state, subkey, 28);
+ camelliaF2(state, subkey, 32);
+ camelliaFLs(state, ke, 8);
+ camelliaF2(state, subkey, 36);
+ camelliaF2(state, subkey, 40);
+ camelliaF2(state, subkey, 44);
+
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output[4..]);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output[8..]);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output[12..]);
+
+ return BLOCK_SIZE;
+ }
+#else
+ private int ProcessBlock128(byte[] input, int inOff, byte[] output, int outOff)
{
uint[] state = new uint[4];
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
+ state[i] = Pack.BE_To_UInt32(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -470,26 +502,21 @@ namespace Org.BouncyCastle.Crypto.Engines
camelliaF2(state, subkey, 28);
camelliaF2(state, subkey, 32);
- state[2] ^= kw[4];
- state[3] ^= kw[5];
- state[0] ^= kw[6];
- state[1] ^= kw[7];
-
- uint2bytes(state[2], output, outOff);
- uint2bytes(state[3], output, outOff + 4);
- uint2bytes(state[0], output, outOff + 8);
- uint2bytes(state[1], output, outOff + 12);
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output, outOff);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output, outOff + 4);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output, outOff + 8);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output, outOff + 12);
return BLOCK_SIZE;
}
- private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
+ private int ProcessBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
{
uint[] state = new uint[4];
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
+ state[i] = Pack.BE_To_UInt32(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -508,18 +535,14 @@ namespace Org.BouncyCastle.Crypto.Engines
camelliaF2(state, subkey, 40);
camelliaF2(state, subkey, 44);
- state[2] ^= kw[4];
- state[3] ^= kw[5];
- state[0] ^= kw[6];
- state[1] ^= kw[7];
-
- uint2bytes(state[2], output, outOff);
- uint2bytes(state[3], output, outOff + 4);
- uint2bytes(state[0], output, outOff + 8);
- uint2bytes(state[1], output, outOff + 12);
+ Pack.UInt32_To_BE(state[2] ^ kw[4], output, outOff);
+ Pack.UInt32_To_BE(state[3] ^ kw[5], output, outOff + 4);
+ Pack.UInt32_To_BE(state[0] ^ kw[6], output, outOff + 8);
+ Pack.UInt32_To_BE(state[1] ^ kw[7], output, outOff + 12);
return BLOCK_SIZE;
}
+#endif
public CamelliaLightEngine()
{
@@ -553,11 +576,7 @@ namespace Org.BouncyCastle.Crypto.Engines
initialised = true;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (!initialised)
throw new InvalidOperationException("Camellia engine not initialised");
@@ -565,17 +584,48 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
- if (_keyis128)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (_keyis128)
+ {
+ return ProcessBlock128(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ return ProcessBlock192or256(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
+ if (_keyis128)
+ {
+ return ProcessBlock128(input, inOff, output, outOff);
+ }
+ else
+ {
+ return ProcessBlock192or256(input, inOff, output, outOff);
+ }
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Camellia engine not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ if (_keyis128)
{
- return processBlock128(input, inOff, output, outOff);
+ return ProcessBlock128(input, output);
}
else
{
- return processBlock192or256(input, inOff, output, outOff);
+ return ProcessBlock192or256(input, output);
}
}
+#endif
- public virtual void Reset()
+ public virtual void Reset()
{
}
}
diff --git a/crypto/src/crypto/engines/Cast5Engine.cs b/crypto/src/crypto/engines/Cast5Engine.cs
index 398f6d43a..93288a237 100644
--- a/crypto/src/crypto/engines/Cast5Engine.cs
+++ b/crypto/src/crypto/engines/Cast5Engine.cs
@@ -352,19 +352,25 @@ namespace Org.BouncyCastle.Crypto.Engines
get { return false; }
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- int blockSize = GetBlockSize();
if (_workingKey == null)
throw new InvalidOperationException(AlgorithmName + " not initialised");
+ int blockSize = GetBlockSize();
Check.DataLength(input, inOff, blockSize, "input buffer too short");
Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (_encrypting)
+ {
+ return EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ return DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
if (_encrypting)
{
return EncryptBlock(input, inOff, output, outOff);
@@ -373,7 +379,29 @@ namespace Org.BouncyCastle.Crypto.Engines
{
return DecryptBlock(input, inOff, output, outOff);
}
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (_workingKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ int blockSize = GetBlockSize();
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ if (_encrypting)
+ {
+ return EncryptBlock(input, output);
+ }
+ else
+ {
+ return DecryptBlock(input, output);
+ }
}
+#endif
public virtual void Reset()
{
@@ -566,20 +594,45 @@ namespace Org.BouncyCastle.Crypto.Engines
_Kr[16]=(int)((S5[x[0xE]]^S6[x[0xF]]^S7[x[0x1]]^S8[x[0x0]]^S8[x[0xD]])&0x1f);
}
- /**
- * Encrypt the given input starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- *
- * @param src The plaintext buffer
- * @param srcIndex An offset into src
- * @param dst The ciphertext buffer
- * @param dstIndex An offset into dst
- */
- internal virtual int EncryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal virtual int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ // process the input block
+ // batch the units up into a 32 bit chunk and go for it
+ // the array is in bytes, the increment is 8x8 bits = 64
+
+ uint L0 = Pack.BE_To_UInt32(input);
+ uint R0 = Pack.BE_To_UInt32(input[4..]);
+
+ uint[] result = new uint[2];
+ CAST_Encipher(L0, R0, result);
+
+ // now stuff them into the destination block
+ Pack.UInt32_To_BE(result[0], output);
+ Pack.UInt32_To_BE(result[1], output[4..]);
+
+ return BLOCK_SIZE;
+ }
+
+ internal virtual int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ // process the input block
+ // batch the units up into a 32 bit chunk and go for it
+ // the array is in bytes, the increment is 8x8 bits = 64
+ uint L16 = Pack.BE_To_UInt32(input);
+ uint R16 = Pack.BE_To_UInt32(input[4..]);
+
+ uint[] result = new uint[2];
+ CAST_Decipher(L16, R16, result);
+
+ // now stuff them into the destination block
+ Pack.UInt32_To_BE(result[0], output);
+ Pack.UInt32_To_BE(result[1], output[4..]);
+
+ return BLOCK_SIZE;
+ }
+#else
+ internal virtual int EncryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
// process the input block
// batch the units up into a 32 bit chunk and go for it
@@ -598,20 +651,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- /**
- * Decrypt the given input starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- *
- * @param src The plaintext buffer
- * @param srcIndex An offset into src
- * @param dst The ciphertext buffer
- * @param dstIndex An offset into dst
- */
- internal virtual int DecryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+ internal virtual int DecryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
// process the input block
// batch the units up into a 32 bit chunk and go for it
@@ -628,6 +668,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
+#endif
/**
* The first of the three processing functions for the
@@ -702,28 +743,28 @@ namespace Org.BouncyCastle.Crypto.Engines
Li = Rp;
switch (i)
{
- case 1:
- case 4:
- case 7:
- case 10:
- case 13:
- case 16:
- Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
- break;
- case 2:
- case 5:
- case 8:
- case 11:
- case 14:
- Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
- break;
- case 3:
- case 6:
- case 9:
- case 12:
- case 15:
- Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
- break;
+ case 1:
+ case 4:
+ case 7:
+ case 10:
+ case 13:
+ case 16:
+ Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
+ break;
+ case 2:
+ case 5:
+ case 8:
+ case 11:
+ case 14:
+ Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
+ break;
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
+ break;
}
}
@@ -752,28 +793,28 @@ namespace Org.BouncyCastle.Crypto.Engines
Li = Rp;
switch (i)
{
- case 1:
- case 4:
- case 7:
- case 10:
- case 13:
- case 16:
- Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
- break;
- case 2:
- case 5:
- case 8:
- case 11:
- case 14:
- Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
- break;
- case 3:
- case 6:
- case 9:
- case 12:
- case 15:
- Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
- break;
+ case 1:
+ case 4:
+ case 7:
+ case 10:
+ case 13:
+ case 16:
+ Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
+ break;
+ case 2:
+ case 5:
+ case 8:
+ case 11:
+ case 14:
+ Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
+ break;
+ case 3:
+ case 6:
+ case 9:
+ case 12:
+ case 15:
+ Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
+ break;
}
}
diff --git a/crypto/src/crypto/engines/Cast6Engine.cs b/crypto/src/crypto/engines/Cast6Engine.cs
index c5c419b78..c3f379fcf 100644
--- a/crypto/src/crypto/engines/Cast6Engine.cs
+++ b/crypto/src/crypto/engines/Cast6Engine.cs
@@ -134,20 +134,44 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- /**
- * Encrypt the given input starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- *
- * @param src The plaintext buffer
- * @param srcIndex An offset into src
- * @param dst The ciphertext buffer
- * @param dstIndex An offset into dst
- */
- internal override int EncryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ // process the input block
+ // batch the units up into 4x32 bit chunks and go for it
+ uint A = Pack.BE_To_UInt32(input);
+ uint B = Pack.BE_To_UInt32(input[4..]);
+ uint C = Pack.BE_To_UInt32(input[8..]);
+ uint D = Pack.BE_To_UInt32(input[12..]);
+ uint[] result = new uint[4];
+ CAST_Encipher(A, B, C, D, result);
+ // now stuff them into the destination block
+ Pack.UInt32_To_BE(result[0], output);
+ Pack.UInt32_To_BE(result[1], output[4..]);
+ Pack.UInt32_To_BE(result[2], output[8..]);
+ Pack.UInt32_To_BE(result[3], output[12..]);
+ return BLOCK_SIZE;
+ }
+
+ internal override int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ // process the input block
+ // batch the units up into 4x32 bit chunks and go for it
+ uint A = Pack.BE_To_UInt32(input);
+ uint B = Pack.BE_To_UInt32(input[4..]);
+ uint C = Pack.BE_To_UInt32(input[8..]);
+ uint D = Pack.BE_To_UInt32(input[12..]);
+ uint[] result = new uint[4];
+ CAST_Decipher(A, B, C, D, result);
+ // now stuff them into the destination block
+ Pack.UInt32_To_BE(result[0], output);
+ Pack.UInt32_To_BE(result[1], output[4..]);
+ Pack.UInt32_To_BE(result[2], output[8..]);
+ Pack.UInt32_To_BE(result[3], output[12..]);
+ return BLOCK_SIZE;
+ }
+#else
+ internal override int EncryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
// process the input block
// batch the units up into 4x32 bit chunks and go for it
@@ -165,20 +189,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- /**
- * Decrypt the given input starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- *
- * @param src The plaintext buffer
- * @param srcIndex An offset into src
- * @param dst The ciphertext buffer
- * @param dstIndex An offset into dst
- */
- internal override int DecryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+ internal override int DecryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
// process the input block
// batch the units up into 4x32 bit chunks and go for it
@@ -195,8 +206,9 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_BE(result[3], dst, dstIndex + 12);
return BLOCK_SIZE;
}
+#endif
- /**
+ /**
* Does the 12 quad rounds rounds to encrypt the block.
*
* @param A the 00-31 bits of the plaintext block
diff --git a/crypto/src/crypto/engines/DesEdeEngine.cs b/crypto/src/crypto/engines/DesEdeEngine.cs
index 2fac24ac0..ffb18d753 100644
--- a/crypto/src/crypto/engines/DesEdeEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeEngine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
@@ -63,11 +64,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public override int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public override int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey1 == null)
throw new InvalidOperationException("DESede engine not initialised");
@@ -75,23 +72,59 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
- byte[] temp = new byte[BLOCK_SIZE];
+ uint hi32 = Pack.BE_To_UInt32(input, inOff);
+ uint lo32 = Pack.BE_To_UInt32(input, inOff + 4);
if (forEncryption)
{
- DesFunc(workingKey1, input, inOff, temp, 0);
- DesFunc(workingKey2, temp, 0, temp, 0);
- DesFunc(workingKey3, temp, 0, output, outOff);
+ DesFunc(workingKey1, ref hi32, ref lo32);
+ DesFunc(workingKey2, ref hi32, ref lo32);
+ DesFunc(workingKey3, ref hi32, ref lo32);
}
else
{
- DesFunc(workingKey3, input, inOff, temp, 0);
- DesFunc(workingKey2, temp, 0, temp, 0);
- DesFunc(workingKey1, temp, 0, output, outOff);
+ DesFunc(workingKey3, ref hi32, ref lo32);
+ DesFunc(workingKey2, ref hi32, ref lo32);
+ DesFunc(workingKey1, ref hi32, ref lo32);
}
+ Pack.UInt32_To_BE(hi32, output, outOff);
+ Pack.UInt32_To_BE(lo32, output, outOff + 4);
+
+ return BLOCK_SIZE;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (workingKey1 == null)
+ throw new InvalidOperationException("DESede engine not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ uint hi32 = Pack.BE_To_UInt32(input);
+ uint lo32 = Pack.BE_To_UInt32(input[4..]);
+
+ if (forEncryption)
+ {
+ DesFunc(workingKey1, ref hi32, ref lo32);
+ DesFunc(workingKey2, ref hi32, ref lo32);
+ DesFunc(workingKey3, ref hi32, ref lo32);
+ }
+ else
+ {
+ DesFunc(workingKey3, ref hi32, ref lo32);
+ DesFunc(workingKey2, ref hi32, ref lo32);
+ DesFunc(workingKey1, ref hi32, ref lo32);
+ }
+
+ Pack.UInt32_To_BE(hi32, output);
+ Pack.UInt32_To_BE(lo32, output[4..]);
+
return BLOCK_SIZE;
}
+#endif
public override void Reset()
{
diff --git a/crypto/src/crypto/engines/DesEngine.cs b/crypto/src/crypto/engines/DesEngine.cs
index cfd50681e..25f559652 100644
--- a/crypto/src/crypto/engines/DesEngine.cs
+++ b/crypto/src/crypto/engines/DesEngine.cs
@@ -31,10 +31,10 @@ namespace Org.BouncyCastle.Crypto.Engines
bool forEncryption,
ICipherParameters parameters)
{
- if (!(parameters is KeyParameter))
+ if (!(parameters is KeyParameter keyParameter))
throw new ArgumentException("invalid parameter passed to DES init - " + Platform.GetTypeName(parameters));
- workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey());
+ workingKey = GenerateWorkingKey(forEncryption, keyParameter.GetKey());
}
public virtual string AlgorithmName
@@ -52,11 +52,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("DES engine not initialised");
@@ -64,11 +60,38 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
- DesFunc(workingKey, input, inOff, output, outOff);
+ uint hi32 = Pack.BE_To_UInt32(input, inOff);
+ uint lo32 = Pack.BE_To_UInt32(input, inOff + 4);
+
+ DesFunc(workingKey, ref hi32, ref lo32);
+
+ Pack.UInt32_To_BE(hi32, output, outOff);
+ Pack.UInt32_To_BE(lo32, output, outOff + 4);
return BLOCK_SIZE;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("DES engine not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ uint hi32 = Pack.BE_To_UInt32(input);
+ uint lo32 = Pack.BE_To_UInt32(input[4..]);
+
+ DesFunc(workingKey, ref hi32, ref lo32);
+
+ Pack.UInt32_To_BE(hi32, output);
+ Pack.UInt32_To_BE(lo32, output[4..]);
+
+ return BLOCK_SIZE;
+ }
+#endif
+
public virtual void Reset()
{
}
@@ -388,19 +411,11 @@ namespace Org.BouncyCastle.Crypto.Engines
return newKey;
}
- /**
- * the DES engine.
- */
- internal static void DesFunc(
- int[] wKey,
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ internal static void DesFunc(int[] wKey, ref uint hi32, ref uint lo32)
{
- uint left = Pack.BE_To_UInt32(input, inOff);
- uint right = Pack.BE_To_UInt32(input, inOff + 4);
- uint work;
+ uint left = hi32;
+ uint right = lo32;
+ uint work;
work = ((left >> 4) ^ right) & 0x0f0f0f0f;
right ^= work;
@@ -468,8 +483,8 @@ namespace Org.BouncyCastle.Crypto.Engines
left ^= work;
right ^= (work << 4);
- Pack.UInt32_To_BE(right, outBytes, outOff);
- Pack.UInt32_To_BE(left, outBytes, outOff + 4);
+ hi32 = right;
+ lo32 = left;
}
}
}
diff --git a/crypto/src/crypto/engines/Dstu7624Engine.cs b/crypto/src/crypto/engines/Dstu7624Engine.cs
index 844a873a8..a0ff8ebd4 100644
--- a/crypto/src/crypto/engines/Dstu7624Engine.cs
+++ b/crypto/src/crypto/engines/Dstu7624Engine.cs
@@ -268,7 +268,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
case 2:
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ EncryptBlock_128(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
EncryptBlock_128(input, inOff, output, outOff);
+#endif
break;
}
default:
@@ -299,7 +303,11 @@ namespace Org.BouncyCastle.Crypto.Engines
{
case 2:
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ DecryptBlock_128(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
DecryptBlock_128(input, inOff, output, outOff);
+#endif
break;
}
default:
@@ -327,6 +335,82 @@ namespace Org.BouncyCastle.Crypto.Engines
return GetBlockSize();
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Dstu7624Engine not initialised");
+
+ Check.DataLength(input, GetBlockSize(), "input buffer too short");
+ Check.OutputLength(output, GetBlockSize(), "output buffer too short");
+
+ if (forEncryption)
+ {
+ /* Encrypt */
+ switch (wordsInBlock)
+ {
+ case 2:
+ {
+ EncryptBlock_128(input, output);
+ break;
+ }
+ default:
+ {
+ Pack.LE_To_UInt64(input, internalState);
+ AddRoundKey(0);
+ for (int round = 0;;)
+ {
+ EncryptionRound();
+
+ if (++round == roundsAmount)
+ {
+ break;
+ }
+
+ XorRoundKey(round);
+ }
+ AddRoundKey(roundsAmount);
+ Pack.UInt64_To_LE(internalState, output);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Decrypt */
+ switch (wordsInBlock)
+ {
+ case 2:
+ {
+ DecryptBlock_128(input, output);
+ break;
+ }
+ default:
+ {
+ Pack.LE_To_UInt64(input, internalState);
+ SubRoundKey(roundsAmount);
+ for (int round = roundsAmount;;)
+ {
+ DecryptionRound();
+
+ if (--round == 0)
+ {
+ break;
+ }
+
+ XorRoundKey(round);
+ }
+ SubRoundKey(0);
+ Pack.UInt64_To_LE(internalState, output);
+ break;
+ }
+ }
+ }
+
+ return GetBlockSize();
+ }
+#endif
+
private void EncryptionRound()
{
SubBytes();
@@ -341,6 +425,133 @@ namespace Org.BouncyCastle.Crypto.Engines
InvSubBytes();
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void DecryptBlock_128(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ ulong c0 = Pack.LE_To_UInt64(input);
+ ulong c1 = Pack.LE_To_UInt64(input[8..]);
+
+ ulong[] roundKey = roundKeys[roundsAmount];
+ c0 -= roundKey[0];
+ c1 -= roundKey[1];
+
+ for (int round = roundsAmount; ;)
+ {
+ c0 = MixColumnInv(c0);
+ c1 = MixColumnInv(c1);
+
+ uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
+ uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
+
+ {
+ byte t0 = T0[lo0 & 0xFF];
+ byte t1 = T1[(lo0 >> 8) & 0xFF];
+ byte t2 = T2[(lo0 >> 16) & 0xFF];
+ byte t3 = T3[lo0 >> 24];
+ lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = T0[hi1 & 0xFF];
+ byte t5 = T1[(hi1 >> 8) & 0xFF];
+ byte t6 = T2[(hi1 >> 16) & 0xFF];
+ byte t7 = T3[hi1 >> 24];
+ hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c0 = (ulong)lo0 | ((ulong)hi1 << 32);
+ }
+
+ {
+ byte t0 = T0[lo1 & 0xFF];
+ byte t1 = T1[(lo1 >> 8) & 0xFF];
+ byte t2 = T2[(lo1 >> 16) & 0xFF];
+ byte t3 = T3[lo1 >> 24];
+ lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = T0[hi0 & 0xFF];
+ byte t5 = T1[(hi0 >> 8) & 0xFF];
+ byte t6 = T2[(hi0 >> 16) & 0xFF];
+ byte t7 = T3[hi0 >> 24];
+ hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c1 = (ulong)lo1 | ((ulong)hi0 << 32);
+ }
+
+ if (--round == 0)
+ {
+ break;
+ }
+
+ roundKey = roundKeys[round];
+ c0 ^= roundKey[0];
+ c1 ^= roundKey[1];
+ }
+
+ roundKey = roundKeys[0];
+ c0 -= roundKey[0];
+ c1 -= roundKey[1];
+
+ Pack.UInt64_To_LE(c0, output);
+ Pack.UInt64_To_LE(c1, output[8..]);
+ }
+
+ private void EncryptBlock_128(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ ulong c0 = Pack.LE_To_UInt64(input);
+ ulong c1 = Pack.LE_To_UInt64(input[8..]);
+
+ ulong[] roundKey = roundKeys[0];
+ c0 += roundKey[0];
+ c1 += roundKey[1];
+
+ for (int round = 0; ;)
+ {
+ uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
+ uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
+
+ {
+ byte t0 = S0[lo0 & 0xFF];
+ byte t1 = S1[(lo0 >> 8) & 0xFF];
+ byte t2 = S2[(lo0 >> 16) & 0xFF];
+ byte t3 = S3[lo0 >> 24];
+ lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = S0[hi1 & 0xFF];
+ byte t5 = S1[(hi1 >> 8) & 0xFF];
+ byte t6 = S2[(hi1 >> 16) & 0xFF];
+ byte t7 = S3[hi1 >> 24];
+ hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c0 = (ulong)lo0 | ((ulong)hi1 << 32);
+ }
+
+ {
+ byte t0 = S0[lo1 & 0xFF];
+ byte t1 = S1[(lo1 >> 8) & 0xFF];
+ byte t2 = S2[(lo1 >> 16) & 0xFF];
+ byte t3 = S3[lo1 >> 24];
+ lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = S0[hi0 & 0xFF];
+ byte t5 = S1[(hi0 >> 8) & 0xFF];
+ byte t6 = S2[(hi0 >> 16) & 0xFF];
+ byte t7 = S3[hi0 >> 24];
+ hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c1 = (ulong)lo1 | ((ulong)hi0 << 32);
+ }
+
+ c0 = MixColumn(c0);
+ c1 = MixColumn(c1);
+
+ if (++round == roundsAmount)
+ {
+ break;
+ }
+
+ roundKey = roundKeys[round];
+ c0 ^= roundKey[0];
+ c1 ^= roundKey[1];
+ }
+
+ roundKey = roundKeys[roundsAmount];
+ c0 += roundKey[0];
+ c1 += roundKey[1];
+
+ Pack.UInt64_To_LE(c0, output);
+ Pack.UInt64_To_LE(c1, output[8..]);
+ }
+#else
private void DecryptBlock_128(byte[] input, int inOff, byte[] output, int outOff)
{
ulong c0 = Pack.LE_To_UInt64(input, inOff);
@@ -466,6 +677,7 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt64_To_LE(c0, output, outOff);
Pack.UInt64_To_LE(c1, output, outOff + 8);
}
+#endif
private void SubBytes()
{
@@ -900,7 +1112,7 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- #region TABLES AND S-BOXES
+#region TABLES AND S-BOXES
private const ulong mdsMatrix = 0x0407060801050101UL;
private const ulong mdsInvMatrix = 0xCAD7492FA87695ADUL;
@@ -1057,7 +1269,7 @@ namespace Org.BouncyCastle.Crypto.Engines
0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d
};
- #endregion
+#endregion
public virtual string AlgorithmName
{
diff --git a/crypto/src/crypto/engines/GOST28147Engine.cs b/crypto/src/crypto/engines/GOST28147Engine.cs
index 8ef8aeb13..ee5a1ba53 100644
--- a/crypto/src/crypto/engines/GOST28147Engine.cs
+++ b/crypto/src/crypto/engines/GOST28147Engine.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
@@ -151,14 +152,10 @@ namespace Org.BouncyCastle.Crypto.Engines
* @param parameters the parameters required to set up the cipher.
* @exception ArgumentException if the parameters argument is inappropriate.
*/
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
- if (parameters is ParametersWithSBox)
+ if (parameters is ParametersWithSBox param)
{
- ParametersWithSBox param = (ParametersWithSBox)parameters;
-
//
// Set the S-Box
//
@@ -173,14 +170,12 @@ namespace Org.BouncyCastle.Crypto.Engines
//
if (param.Parameters != null)
{
- workingKey = generateWorkingKey(forEncryption,
- ((KeyParameter)param.Parameters).GetKey());
+ workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)param.Parameters).GetKey());
}
}
- else if (parameters is KeyParameter)
+ else if (parameters is KeyParameter keyParameter)
{
- workingKey = generateWorkingKey(forEncryption,
- ((KeyParameter)parameters).GetKey());
+ workingKey = GenerateWorkingKey(forEncryption, keyParameter.GetKey());
}
else if (parameters != null)
{
@@ -204,11 +199,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("Gost28147 engine not initialised");
@@ -216,30 +207,45 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BlockSize, "input buffer too short");
Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
- Gost28147Func(workingKey, input, inOff, output, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Gost28147Func(workingKey, input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ Gost28147Func(workingKey, input, inOff, output, outOff);
+#endif
return BlockSize;
}
- public virtual void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
+ if (workingKey == null)
+ throw new InvalidOperationException("Gost28147 engine not initialised");
+
+ Check.DataLength(input, BlockSize, "input buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
+
+ Gost28147Func(workingKey, input, output);
+
+ return BlockSize;
}
+#endif
- private int[] generateWorkingKey(
- bool forEncryption,
- byte[] userKey)
+ public virtual void Reset()
+ {
+ }
+
+ private int[] GenerateWorkingKey(bool forEncryption, byte[] userKey)
{
this.forEncryption = forEncryption;
if (userKey.Length != 32)
- {
throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!");
- }
int[] key = new int[8];
- for(int i=0; i!=8; i++)
+ for(int i=0; i != 8; i++)
{
- key[i] = bytesToint(userKey,i*4);
+ key[i] = (int)Pack.LE_To_UInt32(userKey, i * 4);
}
return key;
@@ -267,16 +273,12 @@ namespace Org.BouncyCastle.Crypto.Engines
return omLeft | omRight;
}
- private void Gost28147Func(
- int[] workingKey,
- byte[] inBytes,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void Gost28147Func(int[] workingKey, ReadOnlySpan<byte> input, Span<byte> output)
{
- int N1, N2, tmp; //tmp -> for saving N1
- N1 = bytesToint(inBytes, inOff);
- N2 = bytesToint(inBytes, inOff + 4);
+ int N1 = (int)Pack.LE_To_UInt32(input);
+ int N2 = (int)Pack.LE_To_UInt32(input[4..]);
+ int tmp; //tmp -> for saving N1
if (this.forEncryption)
{
@@ -322,30 +324,64 @@ namespace Org.BouncyCastle.Crypto.Engines
N2 = N2 ^ Gost28147_mainStep(N1, workingKey[0]); // 32 step (N1=N1)
- intTobytes(N1, outBytes, outOff);
- intTobytes(N2, outBytes, outOff + 4);
+ Pack.UInt32_To_LE((uint)N1, output);
+ Pack.UInt32_To_LE((uint)N2, output[4..]);
}
-
- //array of bytes to type int
- private static int bytesToint(
- byte[] inBytes,
- int inOff)
+#else
+ private void Gost28147Func(int[] workingKey, byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
- return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
- ((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
- }
+ int N1 = (int)Pack.LE_To_UInt32(inBytes, inOff);
+ int N2 = (int)Pack.LE_To_UInt32(inBytes, inOff + 4);
+ int tmp; //tmp -> for saving N1
- //int to array of bytes
- private static void intTobytes(
- int num,
- byte[] outBytes,
- int outOff)
- {
- outBytes[outOff + 3] = (byte)(num >> 24);
- outBytes[outOff + 2] = (byte)(num >> 16);
- outBytes[outOff + 1] = (byte)(num >> 8);
- outBytes[outOff] = (byte)num;
+ if (this.forEncryption)
+ {
+ for(int k = 0; k < 3; k++) // 1-24 steps
+ {
+ for(int j = 0; j < 8; j++)
+ {
+ tmp = N1;
+ int step = Gost28147_mainStep(N1, workingKey[j]);
+ N1 = N2 ^ step; // CM2
+ N2 = tmp;
+ }
+ }
+ for(int j = 7; j > 0; j--) // 25-31 steps
+ {
+ tmp = N1;
+ N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ }
+ else //decrypt
+ {
+ for(int j = 0; j < 8; j++) // 1-8 steps
+ {
+ tmp = N1;
+ N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ for(int k = 0; k < 3; k++) //9-31 steps
+ {
+ for(int j = 7; j >= 0; j--)
+ {
+ if ((k == 2) && (j==0))
+ {
+ break; // break 32 step
+ }
+ tmp = N1;
+ N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ }
+ }
+
+ N2 = N2 ^ Gost28147_mainStep(N1, workingKey[0]); // 32 step (N1=N1)
+
+ Pack.UInt32_To_LE((uint)N1, outBytes, outOff);
+ Pack.UInt32_To_LE((uint)N2, outBytes, outOff + 4);
}
+#endif
/**
* Return the S-Box associated with SBoxName
diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs
index 6c0379174..c5d3eb36f 100644
--- a/crypto/src/crypto/engines/IdeaEngine.cs
+++ b/crypto/src/crypto/engines/IdeaEngine.cs
@@ -64,11 +64,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("IDEA engine not initialised");
@@ -76,28 +72,59 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ IdeaFunc(workingKey, input.AsSpan(inOff), output.AsSpan(outOff));
+#else
IdeaFunc(workingKey, input, inOff, output, outOff);
+#endif
return BLOCK_SIZE;
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("IDEA engine not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ IdeaFunc(workingKey, input, output);
+ return BLOCK_SIZE;
+ }
+#endif
+
public virtual void Reset()
{
}
- private static readonly int MASK = 0xffff;
- private static readonly int BASE = 0x10001;
- private int BytesToWord(
- byte[] input,
- int inOff)
+
+ private static readonly int MASK = 0xffff;
+ private static readonly int BASE = 0x10001;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int BytesToWord(ReadOnlySpan<byte> input)
+ {
+ return ((input[0] << 8) & 0xff00) + (input[1] & 0xff);
+ }
+
+ private void WordToBytes(int word, Span<byte> output)
+ {
+ output[0] = (byte)((uint)word >> 8);
+ output[1] = (byte)word;
+ }
+#else
+ private int BytesToWord(byte[] input, int inOff)
{
return ((input[inOff] << 8) & 0xff00) + (input[inOff + 1] & 0xff);
}
- private void WordToBytes(
- int word,
- byte[] outBytes,
- int outOff)
+
+ private void WordToBytes(int word, byte[] outBytes, int outOff)
{
outBytes[outOff] = (byte)((uint) word >> 8);
outBytes[outOff + 1] = (byte)word;
}
+#endif
+
/**
* return x = x * y where the multiplication is done modulo
* 65537 (0x10001) (as defined in the IDEA specification) and
@@ -128,19 +155,51 @@ namespace Org.BouncyCastle.Crypto.Engines
}
return x & MASK;
}
- private void IdeaFunc(
- int[] workingKey,
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void IdeaFunc(int[] workingKey, ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int x0 = BytesToWord(input);
+ int x1 = BytesToWord(input[2..]);
+ int x2 = BytesToWord(input[4..]);
+ int x3 = BytesToWord(input[6..]);
+ int keyOff = 0, t0, t1;
+ for (int round = 0; round < 8; round++)
+ {
+ x0 = Mul(x0, workingKey[keyOff++]);
+ x1 += workingKey[keyOff++];
+ x1 &= MASK;
+ x2 += workingKey[keyOff++];
+ x2 &= MASK;
+ x3 = Mul(x3, workingKey[keyOff++]);
+ t0 = x1;
+ t1 = x2;
+ x2 ^= x0;
+ x1 ^= x3;
+ x2 = Mul(x2, workingKey[keyOff++]);
+ x1 += x2;
+ x1 &= MASK;
+ x1 = Mul(x1, workingKey[keyOff++]);
+ x2 += x1;
+ x2 &= MASK;
+ x0 ^= x1;
+ x3 ^= x2;
+ x1 ^= t1;
+ x2 ^= t0;
+ }
+ WordToBytes(Mul(x0, workingKey[keyOff++]), output);
+ WordToBytes(x2 + workingKey[keyOff++], output[2..]); /* NB: Order */
+ WordToBytes(x1 + workingKey[keyOff++], output[4..]);
+ WordToBytes(Mul(x3, workingKey[keyOff]), output[6..]);
+ }
+#else
+ private void IdeaFunc(int[] workingKey, byte[] input, int inOff, byte[] outBytes, int outOff)
{
- int x0, x1, x2, x3, t0, t1;
- int keyOff = 0;
- x0 = BytesToWord(input, inOff);
- x1 = BytesToWord(input, inOff + 2);
- x2 = BytesToWord(input, inOff + 4);
- x3 = BytesToWord(input, inOff + 6);
+ int x0 = BytesToWord(input, inOff);
+ int x1 = BytesToWord(input, inOff + 2);
+ int x2 = BytesToWord(input, inOff + 4);
+ int x3 = BytesToWord(input, inOff + 6);
+ int keyOff = 0, t0, t1;
for (int round = 0; round < 8; round++)
{
x0 = Mul(x0, workingKey[keyOff++]);
@@ -169,16 +228,17 @@ namespace Org.BouncyCastle.Crypto.Engines
WordToBytes(x1 + workingKey[keyOff++], outBytes, outOff + 4);
WordToBytes(Mul(x3, workingKey[keyOff]), outBytes, outOff + 6);
}
+#endif
+
/**
* The following function is used to expand the user key to the encryption
* subkey. The first 16 bytes are the user key, and the rest of the subkey
* is calculated by rotating the previous 16 bytes by 25 bits to the left,
* and so on until the subkey is completed.
*/
- private int[] ExpandKey(
- byte[] uKey)
+ private int[] ExpandKey(byte[] uKey)
{
- int[] key = new int[52];
+ int[] key = new int[52];
if (uKey.Length < 16)
{
byte[] tmp = new byte[16];
@@ -187,7 +247,11 @@ namespace Org.BouncyCastle.Crypto.Engines
}
for (int i = 0; i < 8; i++)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ key[i] = BytesToWord(uKey[(i * 2)..]);
+#else
key[i] = BytesToWord(uKey, i * 2);
+#endif
}
for (int i = 8; i < 52; i++)
{
diff --git a/crypto/src/crypto/engines/NoekeonEngine.cs b/crypto/src/crypto/engines/NoekeonEngine.cs
index 838a40339..2866d8d75 100644
--- a/crypto/src/crypto/engines/NoekeonEngine.cs
+++ b/crypto/src/crypto/engines/NoekeonEngine.cs
@@ -92,11 +92,7 @@ namespace Org.BouncyCastle.Crypto.Engines
this._initialised = true;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
@@ -104,15 +100,179 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, Size, "input buffer too short");
Check.OutputLength(output, outOff, Size, "output buffer too short");
- return _forEncryption
- ? EncryptBlock(input, inOff, output, outOff)
- : DecryptBlock(input, inOff, output, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return _forEncryption
+ ? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
+ : DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ return _forEncryption
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, Size, "input buffer too short");
+ Check.OutputLength(output, Size, "output buffer too short");
+
+ return _forEncryption
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
+ }
+#endif
+
public virtual void Reset()
{
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint a0 = Pack.BE_To_UInt32(input);
+ uint a1 = Pack.BE_To_UInt32(input[4..]);
+ uint a2 = Pack.BE_To_UInt32(input[8..]);
+ uint a3 = Pack.BE_To_UInt32(input[12..]);
+
+ uint k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
+
+ int round = 0;
+ for (;;)
+ {
+ a0 ^= RoundConstants[round];
+
+ // theta(a, k);
+ {
+ uint t02 = a0 ^ a2;
+ t02 ^= Integers.RotateLeft(t02, 8) ^ Integers.RotateLeft(t02, 24);
+
+ a0 ^= k0;
+ a1 ^= k1;
+ a2 ^= k2;
+ a3 ^= k3;
+
+ uint t13 = a1 ^ a3;
+ t13 ^= Integers.RotateLeft(t13, 8) ^ Integers.RotateLeft(t13, 24);
+
+ a0 ^= t13;
+ a1 ^= t02;
+ a2 ^= t13;
+ a3 ^= t02;
+ }
+
+ if (++round > Size)
+ break;
+
+ // pi1(a);
+ {
+ a1 = Integers.RotateLeft(a1, 1);
+ a2 = Integers.RotateLeft(a2, 5);
+ a3 = Integers.RotateLeft(a3, 2);
+ }
+
+ // gamma(a);
+ {
+ uint t = a3;
+ a1 ^= a3 | a2;
+ a3 = a0 ^ (a2 & ~a1);
+
+ a2 = t ^ ~a1 ^ a2 ^ a3;
+
+ a1 ^= a3 | a2;
+ a0 = t ^ (a2 & a1);
+ }
+
+ // pi2(a);
+ {
+ a1 = Integers.RotateLeft(a1, 31);
+ a2 = Integers.RotateLeft(a2, 27);
+ a3 = Integers.RotateLeft(a3, 30);
+ }
+ }
+
+ Pack.UInt32_To_BE(a0, output);
+ Pack.UInt32_To_BE(a1, output[4..]);
+ Pack.UInt32_To_BE(a2, output[8..]);
+ Pack.UInt32_To_BE(a3, output[12..]);
+
+ return Size;
+ }
+
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ uint a0 = Pack.BE_To_UInt32(input);
+ uint a1 = Pack.BE_To_UInt32(input[4..]);
+ uint a2 = Pack.BE_To_UInt32(input[8..]);
+ uint a3 = Pack.BE_To_UInt32(input[12..]);
+
+ uint k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
+
+ int round = Size;
+ for (;;)
+ {
+ // theta(a, k);
+ {
+ uint t02 = a0 ^ a2;
+ t02 ^= Integers.RotateLeft(t02, 8) ^ Integers.RotateLeft(t02, 24);
+
+ a0 ^= k0;
+ a1 ^= k1;
+ a2 ^= k2;
+ a3 ^= k3;
+
+ uint t13 = a1 ^ a3;
+ t13 ^= Integers.RotateLeft(t13, 8) ^ Integers.RotateLeft(t13, 24);
+
+ a0 ^= t13;
+ a1 ^= t02;
+ a2 ^= t13;
+ a3 ^= t02;
+ }
+
+ a0 ^= RoundConstants[round];
+
+ if (--round < 0)
+ break;
+
+ // pi1(a);
+ {
+ a1 = Integers.RotateLeft(a1, 1);
+ a2 = Integers.RotateLeft(a2, 5);
+ a3 = Integers.RotateLeft(a3, 2);
+ }
+
+ // gamma(a);
+ {
+ uint t = a3;
+ a1 ^= a3 | a2;
+ a3 = a0 ^ (a2 & ~a1);
+
+ a2 = t ^ ~a1 ^ a2 ^ a3;
+
+ a1 ^= a3 | a2;
+ a0 = t ^ (a2 & a1);
+ }
+
+ // pi2(a);
+ {
+ a1 = Integers.RotateLeft(a1, 31);
+ a2 = Integers.RotateLeft(a2, 27);
+ a3 = Integers.RotateLeft(a3, 30);
+ }
+ }
+
+ Pack.UInt32_To_BE(a0, output);
+ Pack.UInt32_To_BE(a1, output[4..]);
+ Pack.UInt32_To_BE(a2, output[8..]);
+ Pack.UInt32_To_BE(a3, output[12..]);
+
+ return Size;
+ }
+#else
private int EncryptBlock(byte[] input, int inOff, byte[] output, int outOff)
{
uint a0 = Pack.BE_To_UInt32(input, inOff);
@@ -254,5 +414,6 @@ namespace Org.BouncyCastle.Crypto.Engines
return Size;
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/NullEngine.cs b/crypto/src/crypto/engines/NullEngine.cs
index f883b7c29..b79cfba93 100644
--- a/crypto/src/crypto/engines/NullEngine.cs
+++ b/crypto/src/crypto/engines/NullEngine.cs
@@ -41,11 +41,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (!initialised)
throw new InvalidOperationException("Null engine not initialised");
@@ -61,7 +57,22 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
- public virtual void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Null engine not initialised");
+
+ Check.DataLength(input, BlockSize, "input buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
+
+ input[..BlockSize].CopyTo(output);
+
+ return BlockSize;
+ }
+#endif
+
+ public virtual void Reset()
{
// nothing needs to be done
}
diff --git a/crypto/src/crypto/engines/RC2Engine.cs b/crypto/src/crypto/engines/RC2Engine.cs
index 4aca1894f..972c4128a 100644
--- a/crypto/src/crypto/engines/RC2Engine.cs
+++ b/crypto/src/crypto/engines/RC2Engine.cs
@@ -159,11 +159,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("RC2 engine not initialised");
@@ -171,6 +167,16 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (encrypting)
+ {
+ EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
@@ -179,26 +185,150 @@ namespace Org.BouncyCastle.Crypto.Engines
{
DecryptBlock(input, inOff, output, outOff);
}
+#endif
+
+ return BLOCK_SIZE;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("RC2 engine not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, output);
+ }
+ else
+ {
+ DecryptBlock(input, output);
+ }
return BLOCK_SIZE;
}
+#endif
/**
* return the result rotating the 16 bit number in x left by y
*/
- private int RotateWordLeft(
- int x,
- int y)
+ private int RotateWordLeft(int x, int y)
{
x &= 0xffff;
return (x << y) | (x >> (16 - y));
}
- private void EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((input[7] & 0xff) << 8) + (input[6] & 0xff);
+ x54 = ((input[5] & 0xff) << 8) + (input[4] & 0xff);
+ x32 = ((input[3] & 0xff) << 8) + (input[2] & 0xff);
+ x10 = ((input[1] & 0xff) << 8) + (input[0] & 0xff);
+
+ for (int i = 0; i <= 16; i += 4)
+ {
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i + 1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i + 2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i + 3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 20; i <= 40; i += 4)
+ {
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i + 1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i + 2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i + 3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 44; i < 64; i += 4)
+ {
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i + 1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i + 2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i + 3], 5);
+ }
+
+ output[0] = (byte)x10;
+ output[1] = (byte)(x10 >> 8);
+ output[2] = (byte)x32;
+ output[3] = (byte)(x32 >> 8);
+ output[4] = (byte)x54;
+ output[5] = (byte)(x54 >> 8);
+ output[6] = (byte)x76;
+ output[7] = (byte)(x76 >> 8);
+ }
+
+ private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((input[7] & 0xff) << 8) + (input[6] & 0xff);
+ x54 = ((input[5] & 0xff) << 8) + (input[4] & 0xff);
+ x32 = ((input[3] & 0xff) << 8) + (input[2] & 0xff);
+ x10 = ((input[1] & 0xff) << 8) + (input[0] & 0xff);
+
+ for (int i = 60; i >= 44; i -= 4)
+ {
+ x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i + 3]);
+ x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i + 2]);
+ x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i + 1]);
+ x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 40; i >= 20; i -= 4)
+ {
+ x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i + 3]);
+ x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i + 2]);
+ x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i + 1]);
+ x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 16; i >= 0; i -= 4)
+ {
+ x76 = RotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i + 3]);
+ x54 = RotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i + 2]);
+ x32 = RotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i + 1]);
+ x10 = RotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i]);
+ }
+
+ output[0] = (byte)x10;
+ output[1] = (byte)(x10 >> 8);
+ output[2] = (byte)x32;
+ output[3] = (byte)(x32 >> 8);
+ output[4] = (byte)x54;
+ output[5] = (byte)(x54 >> 8);
+ output[6] = (byte)x76;
+ output[7] = (byte)(x76 >> 8);
+ }
+#else
+ private void EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
int x76, x54, x32, x10;
@@ -209,10 +339,10 @@ namespace Org.BouncyCastle.Crypto.Engines
for (int i = 0; i <= 16; i += 4)
{
- x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
- x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
- x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
- x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
}
x10 += workingKey[x76 & 63];
@@ -222,10 +352,10 @@ namespace Org.BouncyCastle.Crypto.Engines
for (int i = 20; i <= 40; i += 4)
{
- x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
- x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
- x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
- x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
}
x10 += workingKey[x76 & 63];
@@ -235,10 +365,10 @@ namespace Org.BouncyCastle.Crypto.Engines
for (int i = 44; i < 64; i += 4)
{
- x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
- x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
- x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
- x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ x10 = RotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = RotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = RotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = RotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
}
outBytes[outOff + 0] = (byte)x10;
@@ -251,11 +381,7 @@ namespace Org.BouncyCastle.Crypto.Engines
outBytes[outOff + 7] = (byte)(x76 >> 8);
}
- private void DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private void DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
int x76, x54, x32, x10;
@@ -307,5 +433,6 @@ namespace Org.BouncyCastle.Crypto.Engines
outBytes[outOff + 6] = (byte)x76;
outBytes[outOff + 7] = (byte)(x76 >> 8);
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/RC532Engine.cs b/crypto/src/crypto/engines/RC532Engine.cs
index d1c29e624..aa3da5870 100644
--- a/crypto/src/crypto/engines/RC532Engine.cs
+++ b/crypto/src/crypto/engines/RC532Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
@@ -46,7 +47,6 @@ namespace Org.BouncyCastle.Crypto.Engines
public RC532Engine()
{
_noRounds = 12; // the default
-// _S = null;
}
public virtual string AlgorithmName
@@ -72,23 +72,17 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
- if (typeof(RC5Parameters).IsInstanceOfType(parameters))
+ if (parameters is RC5Parameters rc5Parameters)
{
- RC5Parameters p = (RC5Parameters)parameters;
+ _noRounds = rc5Parameters.Rounds;
- _noRounds = p.Rounds;
-
- SetKey(p.GetKey());
+ SetKey(rc5Parameters.GetKey());
}
- else if (typeof(KeyParameter).IsInstanceOfType(parameters))
+ else if (parameters is KeyParameter keyParameter)
{
- KeyParameter p = (KeyParameter)parameters;
-
- SetKey(p.GetKey());
+ SetKey(keyParameter.GetKey());
}
else
{
@@ -98,16 +92,27 @@ namespace Org.BouncyCastle.Crypto.Engines
this.forEncryption = forEncryption;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return forEncryption
+ ? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
+ : DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ return forEncryption
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- return (forEncryption)
- ? EncryptBlock(input, inOff, output, outOff)
- : DecryptBlock(input, inOff, output, outOff);
+ return forEncryption
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
}
+#endif
public virtual void Reset()
{
@@ -118,8 +123,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @param key the key to be used
*/
- private void SetKey(
- byte[] key)
+ private void SetKey(byte[] key)
{
//
// KEY EXPANSION:
@@ -133,7 +137,7 @@ namespace Org.BouncyCastle.Crypto.Engines
// of K. Any unfilled byte positions in L are zeroed. In the
// case that b = c = 0, set c = 1 and L[0] = 0.
//
- int[] L = new int[(key.Length + (4 - 1)) / 4];
+ int[] L = new int[(key.Length + 3) / 4];
for (int i = 0; i != key.Length; i++)
{
@@ -175,120 +179,81 @@ namespace Org.BouncyCastle.Crypto.Engines
for (int k = 0; k < iter; k++)
{
- A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
- B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
+ A = _S[ii] = Integers.RotateLeft(_S[ii] + A + B, 3);
+ B = L[jj] = Integers.RotateLeft(L[jj] + A + B, A + B);
ii = (ii+1) % _S.Length;
jj = (jj+1) % L.Length;
}
}
- /**
- * Encrypt the given block starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- *
- * @param in in byte buffer containing data to encrypt
- * @param inOff offset into src buffer
- * @param out out buffer where encrypted data is written
- * @param outOff offset into out buffer
- */
- private int EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- int A = BytesToWord(input, inOff) + _S[0];
- int B = BytesToWord(input, inOff + 4) + _S[1];
+ int A = (int)Pack.LE_To_UInt32(input) + _S[0];
+ int B = (int)Pack.LE_To_UInt32(input[4..]) + _S[1];
for (int i = 1; i <= _noRounds; i++)
{
- A = RotateLeft(A ^ B, B) + _S[2*i];
- B = RotateLeft(B ^ A, A) + _S[2*i+1];
+ A = Integers.RotateLeft(A ^ B, B) + _S[2*i];
+ B = Integers.RotateLeft(B ^ A, A) + _S[2*i+1];
}
- WordToBytes(A, outBytes, outOff);
- WordToBytes(B, outBytes, outOff + 4);
+ Pack.UInt32_To_LE((uint)A, output);
+ Pack.UInt32_To_LE((uint)B, output[4..]);
- return 2 * 4;
+ return 8;
}
- private int DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- int A = BytesToWord(input, inOff);
- int B = BytesToWord(input, inOff + 4);
+ int A = (int)Pack.LE_To_UInt32(input);
+ int B = (int)Pack.LE_To_UInt32(input[4..]);
for (int i = _noRounds; i >= 1; i--)
{
- B = RotateRight(B - _S[2*i+1], A) ^ A;
- A = RotateRight(A - _S[2*i], B) ^ B;
+ B = Integers.RotateRight(B - _S[2*i+1], A) ^ A;
+ A = Integers.RotateRight(A - _S[2*i], B) ^ B;
}
- WordToBytes(A - _S[0], outBytes, outOff);
- WordToBytes(B - _S[1], outBytes, outOff + 4);
+ Pack.UInt32_To_LE((uint)(A - _S[0]), output);
+ Pack.UInt32_To_LE((uint)(B - _S[1]), output[4..]);
- return 2 * 4;
+ return 8;
}
+#else
+ private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
+ {
+ int A = (int)Pack.LE_To_UInt32(input, inOff) + _S[0];
+ int B = (int)Pack.LE_To_UInt32(input, inOff + 4) + _S[1];
+ for (int i = 1; i <= _noRounds; i++)
+ {
+ A = Integers.RotateLeft(A ^ B, B) + _S[2*i];
+ B = Integers.RotateLeft(B ^ A, A) + _S[2*i+1];
+ }
- //////////////////////////////////////////////////////////////
- //
- // PRIVATE Helper Methods
- //
- //////////////////////////////////////////////////////////////
+ Pack.UInt32_To_LE((uint)A, outBytes, outOff);
+ Pack.UInt32_To_LE((uint)B, outBytes, outOff + 4);
- /**
- * Perform a left "spin" of the word. The rotation of the given
- * word <em>x</em> is rotated left by <em>y</em> bits.
- * Only the <em>lg(32)</em> low-order bits of <em>y</em>
- * are used to determine the rotation amount. Here it is
- * assumed that the wordsize used is a power of 2.
- *
- * @param x word to rotate
- * @param y number of bits to rotate % 32
- */
- private int RotateLeft(int x, int y) {
- return ((int) ( (uint) (x << (y & (32-1))) |
- ((uint) x >> (32 - (y & (32-1)))) )
- );
- }
-
- /**
- * Perform a right "spin" of the word. The rotation of the given
- * word <em>x</em> is rotated left by <em>y</em> bits.
- * Only the <em>lg(32)</em> low-order bits of <em>y</em>
- * are used to determine the rotation amount. Here it is
- * assumed that the wordsize used is a power of 2.
- *
- * @param x word to rotate
- * @param y number of bits to rotate % 32
- */
- private int RotateRight(int x, int y) {
- return ((int) ( ((uint) x >> (y & (32-1))) |
- (uint) (x << (32 - (y & (32-1)))) )
- );
+ return 8;
}
- private int BytesToWord(
- byte[] src,
- int srcOff)
+ private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
- return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8)
- | ((src[srcOff + 2] & 0xff) << 16) | ((src[srcOff + 3] & 0xff) << 24);
- }
+ int A = (int)Pack.LE_To_UInt32(input, inOff);
+ int B = (int)Pack.LE_To_UInt32(input, inOff + 4);
- private void WordToBytes(
- int word,
- byte[] dst,
- int dstOff)
- {
- dst[dstOff] = (byte)word;
- dst[dstOff + 1] = (byte)(word >> 8);
- dst[dstOff + 2] = (byte)(word >> 16);
- dst[dstOff + 3] = (byte)(word >> 24);
+ for (int i = _noRounds; i >= 1; i--)
+ {
+ B = Integers.RotateRight(B - _S[2*i+1], A) ^ A;
+ A = Integers.RotateRight(A - _S[2*i], B) ^ B;
+ }
+
+ Pack.UInt32_To_LE((uint)(A - _S[0]), outBytes, outOff);
+ Pack.UInt32_To_LE((uint)(B - _S[1]), outBytes, outOff + 4);
+
+ return 8;
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/RC564Engine.cs b/crypto/src/crypto/engines/RC564Engine.cs
index 097fd60ba..8d524f420 100644
--- a/crypto/src/crypto/engines/RC564Engine.cs
+++ b/crypto/src/crypto/engines/RC564Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
@@ -15,9 +16,6 @@ namespace Org.BouncyCastle.Crypto.Engines
public class RC564Engine
: IBlockCipher
{
- private static readonly int wordSize = 64;
- private static readonly int bytesPerWord = wordSize / 8;
-
/*
* the number of rounds to perform
*/
@@ -64,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Engines
public virtual int GetBlockSize()
{
- return 2 * bytesPerWord;
+ return 16;
}
/**
@@ -75,33 +73,39 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
- if (!(typeof(RC5Parameters).IsInstanceOfType(parameters)))
- {
+ if (!(parameters is RC5Parameters rc5Parameters))
throw new ArgumentException("invalid parameter passed to RC564 init - " + Platform.GetTypeName(parameters));
- }
-
- RC5Parameters p = (RC5Parameters)parameters;
this.forEncryption = forEncryption;
- _noRounds = p.Rounds;
+ _noRounds = rc5Parameters.Rounds;
- SetKey(p.GetKey());
+ SetKey(rc5Parameters.GetKey());
+ }
+
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return forEncryption
+ ? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
+ : DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ return forEncryption
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+#endif
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- return (forEncryption) ? EncryptBlock(input, inOff, output, outOff)
- : DecryptBlock(input, inOff, output, outOff);
+ return forEncryption
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
}
+#endif
public virtual void Reset()
{
@@ -112,8 +116,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @param key the key to be used
*/
- private void SetKey(
- byte[] key)
+ private void SetKey(byte[] key)
{
//
// KEY EXPANSION:
@@ -127,11 +130,11 @@ namespace Org.BouncyCastle.Crypto.Engines
// of K. Any unfilled byte positions in L are zeroed. In the
// case that b = c = 0, set c = 1 and L[0] = 0.
//
- long[] L = new long[(key.Length + (bytesPerWord - 1)) / bytesPerWord];
+ long[] L = new long[(key.Length + 7) / 8];
for (int i = 0; i != key.Length; i++)
{
- L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord));
+ L[i / 8] += (long)(key[i] & 0xff) << (8 * (i % 8));
}
//
@@ -169,127 +172,81 @@ namespace Org.BouncyCastle.Crypto.Engines
for (int k = 0; k < iter; k++)
{
- A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
- B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
+ A = _S[ii] = Longs.RotateLeft(_S[ii] + A + B, 3);
+ B = L[jj] = Longs.RotateLeft(L[jj] + A + B, (int)(A + B));
ii = (ii+1) % _S.Length;
jj = (jj+1) % L.Length;
}
}
- /**
- * Encrypt the given block starting at the given offset and place
- * the result in the provided buffer starting at the given offset.
- *
- * @param in in byte buffer containing data to encrypt
- * @param inOff offset into src buffer
- * @param out out buffer where encrypted data is written
- * @param outOff offset into out buffer
- */
- private int EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- long A = BytesToWord(input, inOff) + _S[0];
- long B = BytesToWord(input, inOff + bytesPerWord) + _S[1];
+ long A = (long)Pack.LE_To_UInt64(input) + _S[0];
+ long B = (long)Pack.LE_To_UInt64(input[8..]) + _S[1];
for (int i = 1; i <= _noRounds; i++)
{
- A = RotateLeft(A ^ B, B) + _S[2*i];
- B = RotateLeft(B ^ A, A) + _S[2*i+1];
+ A = Longs.RotateLeft(A ^ B, (int)B) + _S[2*i];
+ B = Longs.RotateLeft(B ^ A, (int)A) + _S[2*i+1];
}
- WordToBytes(A, outBytes, outOff);
- WordToBytes(B, outBytes, outOff + bytesPerWord);
+ Pack.UInt64_To_LE((ulong)A, output);
+ Pack.UInt64_To_LE((ulong)B, output[8..]);
- return 2 * bytesPerWord;
+ return 16;
}
- private int DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- long A = BytesToWord(input, inOff);
- long B = BytesToWord(input, inOff + bytesPerWord);
+ long A = (long)Pack.LE_To_UInt64(input);
+ long B = (long)Pack.LE_To_UInt64(input[8..]);
for (int i = _noRounds; i >= 1; i--)
{
- B = RotateRight(B - _S[2*i+1], A) ^ A;
- A = RotateRight(A - _S[2*i], B) ^ B;
+ B = Longs.RotateRight(B - _S[2*i+1], (int)A) ^ A;
+ A = Longs.RotateRight(A - _S[2*i], (int)B) ^ B;
}
- WordToBytes(A - _S[0], outBytes, outOff);
- WordToBytes(B - _S[1], outBytes, outOff + bytesPerWord);
+ Pack.UInt64_To_LE((ulong)(A - _S[0]), output);
+ Pack.UInt64_To_LE((ulong)(B - _S[1]), output[8..]);
- return 2 * bytesPerWord;
+ return 16;
}
+#else
+ private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
+ {
+ long A = (long)Pack.LE_To_UInt64(input, inOff) + _S[0];
+ long B = (long)Pack.LE_To_UInt64(input, inOff + 8) + _S[1];
+ for (int i = 1; i <= _noRounds; i++)
+ {
+ A = Longs.RotateLeft(A ^ B, (int)B) + _S[2*i];
+ B = Longs.RotateLeft(B ^ A, (int)A) + _S[2*i+1];
+ }
- //////////////////////////////////////////////////////////////
- //
- // PRIVATE Helper Methods
- //
- //////////////////////////////////////////////////////////////
-
- /**
- * Perform a left "spin" of the word. The rotation of the given
- * word <em>x</em> is rotated left by <em>y</em> bits.
- * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
- * are used to determine the rotation amount. Here it is
- * assumed that the wordsize used is a power of 2.
- *
- * @param x word to rotate
- * @param y number of bits to rotate % wordSize
- */
- private long RotateLeft(long x, long y) {
- return ((long) ( (ulong) (x << (int) (y & (wordSize-1))) |
- ((ulong) x >> (int) (wordSize - (y & (wordSize-1)))))
- );
- }
+ Pack.UInt64_To_LE((ulong)A, outBytes, outOff);
+ Pack.UInt64_To_LE((ulong)B, outBytes, outOff + 8);
- /**
- * Perform a right "spin" of the word. The rotation of the given
- * word <em>x</em> is rotated left by <em>y</em> bits.
- * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
- * are used to determine the rotation amount. Here it is
- * assumed that the wordsize used is a power of 2.
- *
- * @param x word to rotate
- * @param y number of bits to rotate % wordSize
- */
- private long RotateRight(long x, long y) {
- return ((long) ( ((ulong) x >> (int) (y & (wordSize-1))) |
- (ulong) (x << (int) (wordSize - (y & (wordSize-1)))))
- );
+ return 16;
}
- private long BytesToWord(
- byte[] src,
- int srcOff)
+ private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
- long word = 0;
+ long A = (long)Pack.LE_To_UInt64(input, inOff);
+ long B = (long)Pack.LE_To_UInt64(input, inOff + 8);
- for (int i = bytesPerWord - 1; i >= 0; i--)
+ for (int i = _noRounds; i >= 1; i--)
{
- word = (word << 8) + (src[i + srcOff] & 0xff);
+ B = Longs.RotateRight(B - _S[2*i+1], (int)A) ^ A;
+ A = Longs.RotateRight(A - _S[2*i], (int)B) ^ B;
}
- return word;
- }
+ Pack.UInt64_To_LE((ulong)(A - _S[0]), outBytes, outOff);
+ Pack.UInt64_To_LE((ulong)(B - _S[1]), outBytes, outOff + 8);
- private void WordToBytes(
- long word,
- byte[] dst,
- int dstOff)
- {
- for (int i = 0; i < bytesPerWord; i++)
- {
- dst[i + dstOff] = (byte)word;
- word = (long) ((ulong) word >> 8);
- }
+ return 16;
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/RC6Engine.cs b/crypto/src/crypto/engines/RC6Engine.cs
index 9aeb1e7cb..316bae65e 100644
--- a/crypto/src/crypto/engines/RC6Engine.cs
+++ b/crypto/src/crypto/engines/RC6Engine.cs
@@ -1,6 +1,7 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
@@ -11,9 +12,6 @@ namespace Org.BouncyCastle.Crypto.Engines
public class RC6Engine
: IBlockCipher
{
- private static readonly int wordSize = 32;
- private static readonly int bytesPerWord = wordSize / 8;
-
/*
* the number of rounds to perform
*/
@@ -46,7 +44,6 @@ namespace Org.BouncyCastle.Crypto.Engines
*/
public RC6Engine()
{
-// _S = null;
}
public virtual string AlgorithmName
@@ -61,7 +58,7 @@ namespace Org.BouncyCastle.Crypto.Engines
public virtual int GetBlockSize()
{
- return 4 * bytesPerWord;
+ return 16;
}
/**
@@ -72,36 +69,51 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
- if (!(parameters is KeyParameter))
+ if (!(parameters is KeyParameter keyParameter))
throw new ArgumentException("invalid parameter passed to RC6 init - " + Platform.GetTypeName(parameters));
this.forEncryption = forEncryption;
- KeyParameter p = (KeyParameter)parameters;
- SetKey(p.GetKey());
+ SetKey(keyParameter.GetKey());
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- int blockSize = GetBlockSize();
if (_S == null)
throw new InvalidOperationException("RC6 engine not initialised");
+ int blockSize = GetBlockSize();
Check.DataLength(input, inOff, blockSize, "input buffer too short");
Check.OutputLength(output, outOff, blockSize, "output buffer too short");
- return (forEncryption)
- ? EncryptBlock(input, inOff, output, outOff)
- : DecryptBlock(input, inOff, output, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return forEncryption
+ ? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
+ : DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ return forEncryption
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (_S == null)
+ throw new InvalidOperationException("RC6 engine not initialised");
+
+ int blockSize = GetBlockSize();
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ return forEncryption
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
}
+#endif
public virtual void Reset()
{
@@ -128,17 +140,17 @@ namespace Org.BouncyCastle.Crypto.Engines
// case that b = c = 0, set c = 1 and L[0] = 0.
//
// compute number of dwords
- int c = (key.Length + (bytesPerWord - 1)) / bytesPerWord;
+ int c = (key.Length + 3) / 4;
if (c == 0)
{
c = 1;
}
- int[] L = new int[(key.Length + bytesPerWord - 1) / bytesPerWord];
+ int[] L = new int[(key.Length + 3) / 4];
// load all key bytes into array of key dwords
for (int i = key.Length - 1; i >= 0; i--)
{
- L[i / bytesPerWord] = (L[i / bytesPerWord] << 8) + (key[i] & 0xff);
+ L[i / 4] = (L[i / 4] << 8) + (key[i] & 0xff);
}
//
@@ -178,24 +190,21 @@ namespace Org.BouncyCastle.Crypto.Engines
for (int k = 0; k < iter; k++)
{
- A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
- B = L[jj] = RotateLeft( L[jj] + A + B, A+B);
+ A = _S[ii] = Integers.RotateLeft(_S[ii] + A + B, 3);
+ B = L[jj] = Integers.RotateLeft( L[jj] + A + B, A + B);
ii = (ii+1) % _S.Length;
jj = (jj+1) % L.Length;
}
}
- private int EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
// load A,B,C and D registers from in.
- int A = BytesToWord(input, inOff);
- int B = BytesToWord(input, inOff + bytesPerWord);
- int C = BytesToWord(input, inOff + bytesPerWord*2);
- int D = BytesToWord(input, inOff + bytesPerWord*3);
+ int A = (int)Pack.LE_To_UInt32(input);
+ int B = (int)Pack.LE_To_UInt32(input[4..]);
+ int C = (int)Pack.LE_To_UInt32(input[8..]);
+ int D = (int)Pack.LE_To_UInt32(input[12..]);
// Do pseudo-round #0: pre-whitening of B and D
B += _S[0];
@@ -204,21 +213,21 @@ namespace Org.BouncyCastle.Crypto.Engines
// perform round #1,#2 ... #ROUNDS of encryption
for (int i = 1; i <= _noRounds; i++)
{
- int t = 0,u = 0;
+ int t = 0, u = 0;
- t = B*(2*B+1);
- t = RotateLeft(t,5);
+ t = B * (2 * B + 1);
+ t = Integers.RotateLeft(t, 5);
- u = D*(2*D+1);
- u = RotateLeft(u,5);
+ u = D * (2 * D + 1);
+ u = Integers.RotateLeft(u, 5);
A ^= t;
- A = RotateLeft(A,u);
- A += _S[2*i];
+ A = Integers.RotateLeft(A, u);
+ A += _S[2 * i];
C ^= u;
- C = RotateLeft(C,t);
- C += _S[2*i+1];
+ C = Integers.RotateLeft(C, t);
+ C += _S[2 * i + 1];
int temp = A;
A = B;
@@ -226,39 +235,36 @@ namespace Org.BouncyCastle.Crypto.Engines
C = D;
D = temp;
}
+
// do pseudo-round #(ROUNDS+1) : post-whitening of A and C
- A += _S[2*_noRounds+2];
- C += _S[2*_noRounds+3];
+ A += _S[2 * _noRounds + 2];
+ C += _S[2 * _noRounds + 3];
// store A, B, C and D registers to out
- WordToBytes(A, outBytes, outOff);
- WordToBytes(B, outBytes, outOff + bytesPerWord);
- WordToBytes(C, outBytes, outOff + bytesPerWord*2);
- WordToBytes(D, outBytes, outOff + bytesPerWord*3);
+ Pack.UInt32_To_LE((uint)A, output);
+ Pack.UInt32_To_LE((uint)B, output[4..]);
+ Pack.UInt32_To_LE((uint)C, output[8..]);
+ Pack.UInt32_To_LE((uint)D, output[12..]);
- return 4 * bytesPerWord;
+ return 16;
}
- private int DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
// load A,B,C and D registers from out.
- int A = BytesToWord(input, inOff);
- int B = BytesToWord(input, inOff + bytesPerWord);
- int C = BytesToWord(input, inOff + bytesPerWord*2);
- int D = BytesToWord(input, inOff + bytesPerWord*3);
+ int A = (int)Pack.LE_To_UInt32(input);
+ int B = (int)Pack.LE_To_UInt32(input[4..]);
+ int C = (int)Pack.LE_To_UInt32(input[8..]);
+ int D = (int)Pack.LE_To_UInt32(input[12..]);
// Undo pseudo-round #(ROUNDS+1) : post whitening of A and C
- C -= _S[2*_noRounds+3];
- A -= _S[2*_noRounds+2];
+ C -= _S[2 * _noRounds + 3];
+ A -= _S[2 * _noRounds + 2];
// Undo round #ROUNDS, .., #2,#1 of encryption
for (int i = _noRounds; i >= 1; i--)
{
- int t=0,u = 0;
+ int t = 0, u = 0;
int temp = D;
D = C;
@@ -266,96 +272,133 @@ namespace Org.BouncyCastle.Crypto.Engines
B = A;
A = temp;
- t = B*(2*B+1);
- t = RotateLeft(t, LGW);
+ t = B * (2 * B + 1);
+ t = Integers.RotateLeft(t, LGW);
- u = D*(2*D+1);
- u = RotateLeft(u, LGW);
+ u = D * (2 * D + 1);
+ u = Integers.RotateLeft(u, LGW);
- C -= _S[2*i+1];
- C = RotateRight(C,t);
+ C -= _S[2 * i + 1];
+ C = Integers.RotateRight(C, t);
C ^= u;
- A -= _S[2*i];
- A = RotateRight(A,u);
+ A -= _S[2 * i];
+ A = Integers.RotateRight(A, u);
A ^= t;
-
}
+
// Undo pseudo-round #0: pre-whitening of B and D
D -= _S[1];
B -= _S[0];
- WordToBytes(A, outBytes, outOff);
- WordToBytes(B, outBytes, outOff + bytesPerWord);
- WordToBytes(C, outBytes, outOff + bytesPerWord*2);
- WordToBytes(D, outBytes, outOff + bytesPerWord*3);
+ Pack.UInt32_To_LE((uint)A, output);
+ Pack.UInt32_To_LE((uint)B, output[4..]);
+ Pack.UInt32_To_LE((uint)C, output[8..]);
+ Pack.UInt32_To_LE((uint)D, output[12..]);
- return 4 * bytesPerWord;
+ return 16;
}
+#else
+ private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
+ {
+ // load A,B,C and D registers from in.
+ int A = (int)Pack.LE_To_UInt32(input, inOff);
+ int B = (int)Pack.LE_To_UInt32(input, inOff + 4);
+ int C = (int)Pack.LE_To_UInt32(input, inOff + 8);
+ int D = (int)Pack.LE_To_UInt32(input, inOff + 12);
+ // Do pseudo-round #0: pre-whitening of B and D
+ B += _S[0];
+ D += _S[1];
- //////////////////////////////////////////////////////////////
- //
- // PRIVATE Helper Methods
- //
- //////////////////////////////////////////////////////////////
+ // perform round #1,#2 ... #ROUNDS of encryption
+ for (int i = 1; i <= _noRounds; i++)
+ {
+ int t = 0,u = 0;
- /**
- * Perform a left "spin" of the word. The rotation of the given
- * word <em>x</em> is rotated left by <em>y</em> bits.
- * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
- * are used to determine the rotation amount. Here it is
- * assumed that the wordsize used is a power of 2.
- *
- * @param x word to rotate
- * @param y number of bits to rotate % wordSize
- */
- private int RotateLeft(int x, int y)
- {
- return ((int)((uint)(x << (y & (wordSize-1)))
- | ((uint) x >> (wordSize - (y & (wordSize-1))))));
- }
+ t = B*(2*B+1);
+ t = Integers.RotateLeft(t,5);
- /**
- * Perform a right "spin" of the word. The rotation of the given
- * word <em>x</em> is rotated left by <em>y</em> bits.
- * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
- * are used to determine the rotation amount. Here it is
- * assumed that the wordsize used is a power of 2.
- *
- * @param x word to rotate
- * @param y number of bits to rotate % wordSize
- */
- private int RotateRight(int x, int y)
- {
- return ((int)(((uint) x >> (y & (wordSize-1)))
- | (uint)(x << (wordSize - (y & (wordSize-1))))));
- }
+ u = D*(2*D+1);
+ u = Integers.RotateLeft(u,5);
- private int BytesToWord(
- byte[] src,
- int srcOff)
- {
- int word = 0;
+ A ^= t;
+ A = Integers.RotateLeft(A,u);
+ A += _S[2*i];
- for (int i = bytesPerWord - 1; i >= 0; i--)
- {
- word = (word << 8) + (src[i + srcOff] & 0xff);
+ C ^= u;
+ C = Integers.RotateLeft(C,t);
+ C += _S[2*i+1];
+
+ int temp = A;
+ A = B;
+ B = C;
+ C = D;
+ D = temp;
}
- return word;
+ // do pseudo-round #(ROUNDS+1) : post-whitening of A and C
+ A += _S[2*_noRounds+2];
+ C += _S[2*_noRounds+3];
+
+ // store A, B, C and D registers to out
+ Pack.UInt32_To_LE((uint)A, outBytes, outOff);
+ Pack.UInt32_To_LE((uint)B, outBytes, outOff + 4);
+ Pack.UInt32_To_LE((uint)C, outBytes, outOff + 8);
+ Pack.UInt32_To_LE((uint)D, outBytes, outOff + 12);
+
+ return 16;
}
- private void WordToBytes(
- int word,
- byte[] dst,
- int dstOff)
+ private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
- for (int i = 0; i < bytesPerWord; i++)
+ // load A,B,C and D registers from out.
+ int A = (int)Pack.LE_To_UInt32(input, inOff);
+ int B = (int)Pack.LE_To_UInt32(input, inOff + 4);
+ int C = (int)Pack.LE_To_UInt32(input, inOff + 8);
+ int D = (int)Pack.LE_To_UInt32(input, inOff + 12);
+
+ // Undo pseudo-round #(ROUNDS+1) : post whitening of A and C
+ C -= _S[2*_noRounds+3];
+ A -= _S[2*_noRounds+2];
+
+ // Undo round #ROUNDS, .., #2,#1 of encryption
+ for (int i = _noRounds; i >= 1; i--)
{
- dst[i + dstOff] = (byte)word;
- word = (int) ((uint) word >> 8);
+ int t=0,u = 0;
+
+ int temp = D;
+ D = C;
+ C = B;
+ B = A;
+ A = temp;
+
+ t = B*(2*B+1);
+ t = Integers.RotateLeft(t, LGW);
+
+ u = D*(2*D+1);
+ u = Integers.RotateLeft(u, LGW);
+
+ C -= _S[2*i+1];
+ C = Integers.RotateRight(C,t);
+ C ^= u;
+
+ A -= _S[2*i];
+ A = Integers.RotateRight(A,u);
+ A ^= t;
}
+
+ // Undo pseudo-round #0: pre-whitening of B and D
+ D -= _S[1];
+ B -= _S[0];
+
+ Pack.UInt32_To_LE((uint)A, outBytes, outOff);
+ Pack.UInt32_To_LE((uint)B, outBytes, outOff + 4);
+ Pack.UInt32_To_LE((uint)C, outBytes, outOff + 8);
+ Pack.UInt32_To_LE((uint)D, outBytes, outOff + 12);
+
+ return 16;
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/RijndaelEngine.cs b/crypto/src/crypto/engines/RijndaelEngine.cs
index 7025cb5dc..2bd404973 100644
--- a/crypto/src/crypto/engines/RijndaelEngine.cs
+++ b/crypto/src/crypto/engines/RijndaelEngine.cs
@@ -601,11 +601,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BC / 2;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("Rijndael engine not initialised");
@@ -613,7 +609,11 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, (BC / 2), "input buffer too short");
Check.OutputLength(output, outOff, (BC / 2), "output buffer too short");
- UnPackBlock(input, inOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ UnPackBlock(input.AsSpan(inOff));
+#else
+ UnPackBlock(input, inOff);
+#endif
if (forEncryption)
{
@@ -624,20 +624,80 @@ namespace Org.BouncyCastle.Crypto.Engines
DecryptBlock(workingKey);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ PackBlock(output.AsSpan(outOff));
+#else
PackBlock(output, outOff);
+#endif
return BC / 2;
}
- public virtual void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
+ if (workingKey == null)
+ throw new InvalidOperationException("Rijndael engine not initialised");
+
+ Check.DataLength(input, (BC / 2), "input buffer too short");
+ Check.OutputLength(output, (BC / 2), "output buffer too short");
+
+ UnPackBlock(input);
+
+ if (forEncryption)
+ {
+ EncryptBlock(workingKey);
+ }
+ else
+ {
+ DecryptBlock(workingKey);
+ }
+
+ PackBlock(output);
+
+ return BC / 2;
}
+#endif
- private void UnPackBlock(
- byte[] bytes,
- int off)
+ public virtual void Reset()
+ {
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void UnPackBlock(ReadOnlySpan<byte> input)
+ {
+ int index = 0;
+
+ A0 = (long)(input[index++] & 0xff);
+ A1 = (long)(input[index++] & 0xff);
+ A2 = (long)(input[index++] & 0xff);
+ A3 = (long)(input[index++] & 0xff);
+
+ for (int j = 8; j != BC; j += 8)
+ {
+ A0 |= (long)(input[index++] & 0xff) << j;
+ A1 |= (long)(input[index++] & 0xff) << j;
+ A2 |= (long)(input[index++] & 0xff) << j;
+ A3 |= (long)(input[index++] & 0xff) << j;
+ }
+ }
+
+ private void PackBlock(Span<byte> output)
+ {
+ int index = 0;
+
+ for (int j = 0; j != BC; j += 8)
+ {
+ output[index++] = (byte)(A0 >> j);
+ output[index++] = (byte)(A1 >> j);
+ output[index++] = (byte)(A2 >> j);
+ output[index++] = (byte)(A3 >> j);
+ }
+ }
+#else
+ private void UnPackBlock(byte[] bytes, int off)
{
- int index = off;
+ int index = off;
A0 = (long)(bytes[index++] & 0xff);
A1 = (long)(bytes[index++] & 0xff);
@@ -653,11 +713,9 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- private void PackBlock(
- byte[] bytes,
- int off)
+ private void PackBlock(byte[] bytes, int off)
{
- int index = off;
+ int index = off;
for (int j = 0; j != BC; j += 8)
{
@@ -667,8 +725,9 @@ namespace Org.BouncyCastle.Crypto.Engines
bytes[index++] = (byte)(A3 >> j);
}
}
+#endif
- private void EncryptBlock(
+ private void EncryptBlock(
long[][] rk)
{
int r;
diff --git a/crypto/src/crypto/engines/SEEDEngine.cs b/crypto/src/crypto/engines/SEEDEngine.cs
index d4142c867..6b511e4cc 100644
--- a/crypto/src/crypto/engines/SEEDEngine.cs
+++ b/crypto/src/crypto/engines/SEEDEngine.cs
@@ -1,5 +1,7 @@
using System;
+
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -168,12 +170,10 @@ namespace Org.BouncyCastle.Crypto.Engines
private int[] wKey;
private bool forEncryption;
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
- wKey = createWorkingKey(((KeyParameter)parameters).GetKey());
+ wKey = CreateWorkingKey(((KeyParameter)parameters).GetKey());
}
public virtual string AlgorithmName
@@ -191,11 +191,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
- public virtual int ProcessBlock(
- byte[] inBuf,
- int inOff,
- byte[] outBuf,
- int outOff)
+ public virtual int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
{
if (wKey == null)
throw new InvalidOperationException("SEED engine not initialised");
@@ -203,8 +199,47 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(inBuf, inOff, BlockSize, "input buffer too short");
Check.OutputLength(outBuf, outOff, BlockSize, "output buffer too short");
- long l = bytesToLong(inBuf, inOff + 0);
- long r = bytesToLong(inBuf, inOff + 8);
+ long l = (long)Pack.BE_To_UInt64(inBuf, inOff + 0);
+ long r = (long)Pack.BE_To_UInt64(inBuf, inOff + 8);
+
+ if (forEncryption)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ long nl = r;
+
+ r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
+ l = nl;
+ }
+ }
+ else
+ {
+ for (int i = 15; i >= 0; i--)
+ {
+ long nl = r;
+
+ r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
+ l = nl;
+ }
+ }
+
+ Pack.UInt64_To_BE((ulong)r, outBuf, outOff + 0);
+ Pack.UInt64_To_BE((ulong)l, outBuf, outOff + 8);
+
+ return BlockSize;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (wKey == null)
+ throw new InvalidOperationException("SEED engine not initialised");
+
+ Check.DataLength(input, BlockSize, "input buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
+
+ long l = (long)Pack.BE_To_UInt64(input);
+ long r = (long)Pack.BE_To_UInt64(input[8..]);
if (forEncryption)
{
@@ -227,25 +262,25 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- longToBytes(outBuf, outOff + 0, r);
- longToBytes(outBuf, outOff + 8, l);
+ Pack.UInt64_To_BE((ulong)r, output);
+ Pack.UInt64_To_BE((ulong)l, output[8..]);
return BlockSize;
}
+#endif
- public virtual void Reset()
+ public virtual void Reset()
{
}
- private int[] createWorkingKey(
- byte[] inKey)
+ private int[] CreateWorkingKey(byte[] inKey)
{
if (inKey.Length != 16)
throw new ArgumentException("key size must be 128 bits");
int[] key = new int[32];
- long lower = bytesToLong(inKey, 0);
- long upper = bytesToLong(inKey, 8);
+ long lower = (long)Pack.BE_To_UInt64(inKey, 0);
+ long upper = (long)Pack.BE_To_UInt64(inKey, 8);
int key0 = extractW0(lower);
int key1 = extractW1(lower);
@@ -298,31 +333,6 @@ namespace Org.BouncyCastle.Crypto.Engines
return ((long)((ulong) x >> 8)) | (x << 56);
}
- private long bytesToLong(
- byte[] src,
- int srcOff)
- {
- long word = 0;
-
- for (int i = 0; i <= 7; i++)
- {
- word = (word << 8) + (src[i + srcOff] & 0xff);
- }
-
- return word;
- }
-
- private void longToBytes(
- byte[] dest,
- int destOff,
- long value)
- {
- for (int i = 0; i < 8; i++)
- {
- dest[i + destOff] = (byte)(value >> ((7 - i) * 8));
- }
- }
-
private int G(
int x)
{
diff --git a/crypto/src/crypto/engines/SM4Engine.cs b/crypto/src/crypto/engines/SM4Engine.cs
index 7477b070e..6a7206a01 100644
--- a/crypto/src/crypto/engines/SM4Engine.cs
+++ b/crypto/src/crypto/engines/SM4Engine.cs
@@ -182,6 +182,37 @@ namespace Org.BouncyCastle.Crypto.Engines
return BlockSize;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (null == rk)
+ throw new InvalidOperationException("SM4 not initialised");
+
+ Check.DataLength(input, BlockSize, "input buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
+
+ uint X0 = Pack.BE_To_UInt32(input);
+ uint X1 = Pack.BE_To_UInt32(input[4..]);
+ uint X2 = Pack.BE_To_UInt32(input[8..]);
+ uint X3 = Pack.BE_To_UInt32(input[12..]);
+
+ for (int i = 0; i < 32; i += 4)
+ {
+ X0 ^= T(X1 ^ X2 ^ X3 ^ rk[i ]); // F0
+ X1 ^= T(X2 ^ X3 ^ X0 ^ rk[i + 1]); // F1
+ X2 ^= T(X3 ^ X0 ^ X1 ^ rk[i + 2]); // F2
+ X3 ^= T(X0 ^ X1 ^ X2 ^ rk[i + 3]); // F3
+ }
+
+ Pack.UInt32_To_BE(X3, output);
+ Pack.UInt32_To_BE(X2, output[4..]);
+ Pack.UInt32_To_BE(X1, output[8..]);
+ Pack.UInt32_To_BE(X0, output[12..]);
+
+ return BlockSize;
+ }
+#endif
+
public virtual void Reset()
{
}
diff --git a/crypto/src/crypto/engines/SerpentEngine.cs b/crypto/src/crypto/engines/SerpentEngine.cs
index 76799f045..00473fa0a 100644
--- a/crypto/src/crypto/engines/SerpentEngine.cs
+++ b/crypto/src/crypto/engines/SerpentEngine.cs
@@ -150,14 +150,130 @@ namespace Org.BouncyCastle.Crypto.Engines
return w;
}
- /**
- * Encrypt one block of plaintext.
- *
- * @param input the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param output the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- */
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ protected override void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ X0 = (int)Pack.LE_To_UInt32(input);
+ X1 = (int)Pack.LE_To_UInt32(input[4..]);
+ X2 = (int)Pack.LE_To_UInt32(input[8..]);
+ X3 = (int)Pack.LE_To_UInt32(input[12..]);
+
+ Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT();
+ Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT();
+ Sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT();
+ Sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT();
+ Sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT();
+ Sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT();
+ Sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT();
+ Sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT();
+ Sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT();
+ Sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT();
+ Sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT();
+ Sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT();
+ Sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT();
+ Sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT();
+ Sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT();
+ Sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT();
+ Sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT();
+ Sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT();
+ Sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT();
+ Sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT();
+ Sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT();
+ Sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT();
+ Sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT();
+ Sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT();
+ Sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT();
+ Sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT();
+ Sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT();
+ Sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT();
+ Sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT();
+ Sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT();
+ Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT();
+ Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
+
+ Pack.UInt32_To_LE((uint)(wKey[128] ^ X0), output);
+ Pack.UInt32_To_LE((uint)(wKey[129] ^ X1), output[4..]);
+ Pack.UInt32_To_LE((uint)(wKey[130] ^ X2), output[8..]);
+ Pack.UInt32_To_LE((uint)(wKey[131] ^ X3), output[12..]);
+ }
+
+ protected override void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ X0 = wKey[128] ^ (int)Pack.LE_To_UInt32(input);
+ X1 = wKey[129] ^ (int)Pack.LE_To_UInt32(input[4..]);
+ X2 = wKey[130] ^ (int)Pack.LE_To_UInt32(input[8..]);
+ X3 = wKey[131] ^ (int)Pack.LE_To_UInt32(input[12..]);
+
+ Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+
+ Pack.UInt32_To_LE((uint)(X0 ^ wKey[0]), output);
+ Pack.UInt32_To_LE((uint)(X1 ^ wKey[1]), output[4..]);
+ Pack.UInt32_To_LE((uint)(X2 ^ wKey[2]), output[8..]);
+ Pack.UInt32_To_LE((uint)(X3 ^ wKey[3]), output[12..]);
+ }
+#else
protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff)
{
X0 = (int)Pack.LE_To_UInt32(input, inOff);
@@ -204,14 +320,6 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_LE((uint)(wKey[131] ^ X3), output, outOff + 12);
}
- /**
- * Decrypt one block of ciphertext.
- *
- * @param input the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param output the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- */
protected override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff)
{
X0 = wKey[128] ^ (int)Pack.LE_To_UInt32(input, inOff);
@@ -288,5 +396,6 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_LE((uint)(X2 ^ wKey[2]), output, outOff + 8);
Pack.UInt32_To_LE((uint)(X3 ^ wKey[3]), output, outOff + 12);
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/SerpentEngineBase.cs b/crypto/src/crypto/engines/SerpentEngineBase.cs
index 9de552233..8ddbc4b6f 100644
--- a/crypto/src/crypto/engines/SerpentEngineBase.cs
+++ b/crypto/src/crypto/engines/SerpentEngineBase.cs
@@ -75,6 +75,16 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BlockSize, "input buffer too short");
Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (encrypting)
+ {
+ EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
@@ -83,9 +93,32 @@ namespace Org.BouncyCastle.Crypto.Engines
{
DecryptBlock(input, inOff, output, outOff);
}
+#endif
+
+ return BlockSize;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (wKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, BlockSize, "input buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, output);
+ }
+ else
+ {
+ DecryptBlock(input, output);
+ }
return BlockSize;
}
+#endif
public virtual void Reset()
{
@@ -462,8 +495,12 @@ namespace Org.BouncyCastle.Crypto.Engines
protected abstract int[] MakeWorkingKey(byte[] key);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ protected abstract void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output);
+ protected abstract void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output);
+#else
protected abstract void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff);
-
protected abstract void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff);
+#endif
}
}
diff --git a/crypto/src/crypto/engines/SkipjackEngine.cs b/crypto/src/crypto/engines/SkipjackEngine.cs
index c90646cc4..e78111abd 100644
--- a/crypto/src/crypto/engines/SkipjackEngine.cs
+++ b/crypto/src/crypto/engines/SkipjackEngine.cs
@@ -87,11 +87,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (key1 == null)
throw new InvalidOperationException("SKIPJACK engine not initialised");
@@ -99,6 +95,16 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (encrypting)
+ {
+ EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
@@ -107,10 +113,33 @@ namespace Org.BouncyCastle.Crypto.Engines
{
DecryptBlock(input, inOff, output, outOff);
}
+#endif
return BLOCK_SIZE;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (key1 == null)
+ throw new InvalidOperationException("SKIPJACK engine not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, output);
+ }
+ else
+ {
+ DecryptBlock(input, output);
+ }
+
+ return BLOCK_SIZE;
+ }
+#endif
+
public virtual void Reset()
{
}
@@ -135,11 +164,97 @@ namespace Org.BouncyCastle.Crypto.Engines
return ((g5 << 8) + g6);
}
- public virtual int EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int w1 = (input[0] << 8) + (input[1] & 0xff);
+ int w2 = (input[2] << 8) + (input[3] & 0xff);
+ int w3 = (input[4] << 8) + (input[5] & 0xff);
+ int w4 = (input[6] << 8) + (input[7] & 0xff);
+
+ int k = 0;
+
+ for (int t = 0; t < 2; t++)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w2;
+ w2 = G(k, w1);
+ w1 = w2 ^ tmp ^ (k + 1);
+ k++;
+ }
+
+ for (int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w1 ^ w2 ^ (k + 1);
+ w2 = G(k, w1);
+ w1 = tmp;
+ k++;
+ }
+ }
+
+ output[0] = (byte)((w1 >> 8));
+ output[1] = (byte)(w1);
+ output[2] = (byte)((w2 >> 8));
+ output[3] = (byte)(w2);
+ output[4] = (byte)((w3 >> 8));
+ output[5] = (byte)(w3);
+ output[6] = (byte)((w4 >> 8));
+ output[7] = (byte)(w4);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int w2 = (input[0] << 8) + (input[1] & 0xff);
+ int w1 = (input[2] << 8) + (input[3] & 0xff);
+ int w4 = (input[4] << 8) + (input[5] & 0xff);
+ int w3 = (input[6] << 8) + (input[7] & 0xff);
+
+ int k = 31;
+
+ for (int t = 0; t < 2; t++)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w2;
+ w2 = H(k, w1);
+ w1 = w2 ^ tmp ^ (k + 1);
+ k--;
+ }
+
+ for (int i = 0; i < 8; i++)
+ {
+ int tmp = w4;
+ w4 = w3;
+ w3 = w1 ^ w2 ^ (k + 1);
+ w2 = H(k, w1);
+ w1 = tmp;
+ k--;
+ }
+ }
+
+ output[0] = (byte)((w2 >> 8));
+ output[1] = (byte)(w2);
+ output[2] = (byte)((w1 >> 8));
+ output[3] = (byte)(w1);
+ output[4] = (byte)((w4 >> 8));
+ output[5] = (byte)(w4);
+ output[6] = (byte)((w3 >> 8));
+ output[7] = (byte)(w3);
+
+ return BLOCK_SIZE;
+ }
+
+#else
+ public virtual int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
int w1 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
int w2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
@@ -183,31 +298,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
- /**
- * the inverse of the G permutation.
- */
- private int H(
- int k,
- int w)
- {
- int h1, h2, h3, h4, h5, h6;
-
- h1 = w & 0xff;
- h2 = (w >> 8) & 0xff;
-
- h3 = ftable[h2 ^ key3[k]] ^ h1;
- h4 = ftable[h3 ^ key2[k]] ^ h2;
- h5 = ftable[h4 ^ key1[k]] ^ h3;
- h6 = ftable[h5 ^ key0[k]] ^ h4;
-
- return ((h6 << 8) + h5);
- }
-
- public virtual int DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ public virtual int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
int w2 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
int w1 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
@@ -218,7 +309,7 @@ namespace Org.BouncyCastle.Crypto.Engines
for (int t = 0; t < 2; t++)
{
- for(int i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
int tmp = w4;
w4 = w3;
@@ -228,7 +319,7 @@ namespace Org.BouncyCastle.Crypto.Engines
k--;
}
- for(int i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
int tmp = w4;
w4 = w3;
@@ -250,5 +341,22 @@ namespace Org.BouncyCastle.Crypto.Engines
return BLOCK_SIZE;
}
+#endif
+
+ /**
+ * the inverse of the G permutation.
+ */
+ private int H(int k, int w)
+ {
+ int h1 = w & 0xff;
+ int h2 = (w >> 8) & 0xff;
+
+ int h3 = ftable[h2 ^ key3[k]] ^ h1;
+ int h4 = ftable[h3 ^ key2[k]] ^ h2;
+ int h5 = ftable[h4 ^ key1[k]] ^ h3;
+ int h6 = ftable[h5 ^ key0[k]] ^ h4;
+
+ return (h6 << 8) + h5;
+ }
}
}
diff --git a/crypto/src/crypto/engines/TEAEngine.cs b/crypto/src/crypto/engines/TEAEngine.cs
index 7b700145e..bb6ae6dcc 100644
--- a/crypto/src/crypto/engines/TEAEngine.cs
+++ b/crypto/src/crypto/engines/TEAEngine.cs
@@ -60,11 +60,9 @@ namespace Org.BouncyCastle.Crypto.Engines
* @exception ArgumentException if the params argument is
* inappropriate.
*/
- public virtual void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
- if (!(parameters is KeyParameter))
+ if (!(parameters is KeyParameter keyParameter))
{
throw new ArgumentException("invalid parameter passed to TEA init - "
+ Platform.GetTypeName(parameters));
@@ -73,16 +71,10 @@ namespace Org.BouncyCastle.Crypto.Engines
_forEncryption = forEncryption;
_initialised = true;
- KeyParameter p = (KeyParameter) parameters;
-
- setKey(p.GetKey());
+ SetKey(keyParameter.GetKey());
}
- public virtual int ProcessBlock(
- byte[] inBytes,
- int inOff,
- byte[] outBytes,
- int outOff)
+ public virtual int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
@@ -90,12 +82,33 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(inBytes, inOff, block_size, "input buffer too short");
Check.OutputLength(outBytes, outOff, block_size, "output buffer too short");
- return _forEncryption
- ? encryptBlock(inBytes, inOff, outBytes, outOff)
- : decryptBlock(inBytes, inOff, outBytes, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return _forEncryption
+ ? EncryptBlock(inBytes.AsSpan(inOff), outBytes.AsSpan(outOff))
+ : DecryptBlock(inBytes.AsSpan(inOff), outBytes.AsSpan(outOff));
+#else
+ return _forEncryption
+ ? EncryptBlock(inBytes, inOff, outBytes, outOff)
+ : DecryptBlock(inBytes, inOff, outBytes, outOff);
+#endif
}
- public virtual void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, block_size, "input buffer too short");
+ Check.OutputLength(output, block_size, "output buffer too short");
+
+ return _forEncryption
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
+ }
+#endif
+
+ public virtual void Reset()
{
}
@@ -104,8 +117,7 @@ namespace Org.BouncyCastle.Crypto.Engines
*
* @param key the key to be used
*/
- private void setKey(
- byte[] key)
+ private void SetKey(byte[] key)
{
_a = Pack.BE_To_UInt32(key, 0);
_b = Pack.BE_To_UInt32(key, 4);
@@ -113,18 +125,57 @@ namespace Org.BouncyCastle.Crypto.Engines
_d = Pack.BE_To_UInt32(key, 12);
}
- private int encryptBlock(
- byte[] inBytes,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ // Pack bytes into integers
+ uint v0 = Pack.BE_To_UInt32(input);
+ uint v1 = Pack.BE_To_UInt32(input[4..]);
+
+ uint sum = 0;
+
+ for (int i = 0; i != rounds; i++)
+ {
+ sum += delta;
+ v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >> 5) + _b);
+ v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >> 5) + _d);
+ }
+
+ Pack.UInt32_To_BE(v0, output);
+ Pack.UInt32_To_BE(v1, output[4..]);
+
+ return block_size;
+ }
+
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ // Pack bytes into integers
+ uint v0 = Pack.BE_To_UInt32(input);
+ uint v1 = Pack.BE_To_UInt32(input[4..]);
+
+ uint sum = d_sum;
+
+ for (int i = 0; i != rounds; i++)
+ {
+ v1 -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >> 5) + _d);
+ v0 -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >> 5) + _b);
+ sum -= delta;
+ }
+
+ Pack.UInt32_To_BE(v0, output);
+ Pack.UInt32_To_BE(v1, output[4..]);
+
+ return block_size;
+ }
+#else
+ private int EncryptBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
// Pack bytes into integers
uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
uint v1 = Pack.BE_To_UInt32(inBytes, inOff + 4);
-
+
uint sum = 0;
-
+
for (int i = 0; i != rounds; i++)
{
sum += delta;
@@ -138,11 +189,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return block_size;
}
- private int decryptBlock(
- byte[] inBytes,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private int DecryptBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
// Pack bytes into integers
uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
@@ -162,5 +209,6 @@ namespace Org.BouncyCastle.Crypto.Engines
return block_size;
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/ThreefishEngine.cs b/crypto/src/crypto/engines/ThreefishEngine.cs
index c5aee5395..c22691fc2 100644
--- a/crypto/src/crypto/engines/ThreefishEngine.cs
+++ b/crypto/src/crypto/engines/ThreefishEngine.cs
@@ -285,15 +285,8 @@ namespace Org.BouncyCastle.Crypto.Engines
public virtual int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
- if ((outOff + blocksizeBytes) > outBytes.Length)
- {
- throw new DataLengthException("Output buffer too short");
- }
-
- if ((inOff + blocksizeBytes) > inBytes.Length)
- {
- throw new DataLengthException("Input buffer too short");
- }
+ Check.DataLength(inBytes, inOff, blocksizeBytes, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blocksizeBytes, "output buffer too short");
Pack.LE_To_UInt64(inBytes, inOff, currentBlock);
ProcessBlock(this.currentBlock, this.currentBlock);
@@ -301,6 +294,19 @@ namespace Org.BouncyCastle.Crypto.Engines
return blocksizeBytes;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blocksizeBytes, "input buffer too short");
+ Check.OutputLength(output, blocksizeBytes, "output buffer too short");
+
+ Pack.LE_To_UInt64(input, currentBlock);
+ ProcessBlock(this.currentBlock, this.currentBlock);
+ Pack.UInt64_To_LE(currentBlock, output);
+ return blocksizeBytes;
+ }
+#endif
+
/// <summary>
/// Process a block of data represented as 64 bit words.
/// </summary>
@@ -317,13 +323,9 @@ namespace Org.BouncyCastle.Crypto.Engines
}
if (inWords.Length != blocksizeWords)
- {
- throw new DataLengthException("Input buffer too short");
- }
+ throw new DataLengthException("input buffer too short");
if (outWords.Length != blocksizeWords)
- {
- throw new DataLengthException("Output buffer too short");
- }
+ throw new OutputLengthException("output buffer too short");
if (forEncryption)
{
diff --git a/crypto/src/crypto/engines/TnepresEngine.cs b/crypto/src/crypto/engines/TnepresEngine.cs
index ce687d1e5..cb008a182 100644
--- a/crypto/src/crypto/engines/TnepresEngine.cs
+++ b/crypto/src/crypto/engines/TnepresEngine.cs
@@ -157,14 +157,130 @@ namespace Org.BouncyCastle.Crypto.Engines
return w;
}
- /**
- * Encrypt one block of plaintext.
- *
- * @param input the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param output the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- */
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ protected override void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ X3 = (int)Pack.BE_To_UInt32(input);
+ X2 = (int)Pack.BE_To_UInt32(input[4..]);
+ X1 = (int)Pack.BE_To_UInt32(input[8..]);
+ X0 = (int)Pack.BE_To_UInt32(input[12..]);
+
+ Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT();
+ Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT();
+ Sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT();
+ Sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT();
+ Sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT();
+ Sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT();
+ Sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT();
+ Sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT();
+ Sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT();
+ Sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT();
+ Sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT();
+ Sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT();
+ Sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT();
+ Sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT();
+ Sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT();
+ Sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT();
+ Sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT();
+ Sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT();
+ Sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT();
+ Sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT();
+ Sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT();
+ Sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT();
+ Sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT();
+ Sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT();
+ Sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT();
+ Sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT();
+ Sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT();
+ Sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT();
+ Sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT();
+ Sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT();
+ Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT();
+ Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
+
+ Pack.UInt32_To_BE((uint)(wKey[131] ^ X3), output);
+ Pack.UInt32_To_BE((uint)(wKey[130] ^ X2), output[4..]);
+ Pack.UInt32_To_BE((uint)(wKey[129] ^ X1), output[8..]);
+ Pack.UInt32_To_BE((uint)(wKey[128] ^ X0), output[12..]);
+ }
+
+ protected override void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ X3 = wKey[131] ^ (int)Pack.BE_To_UInt32(input);
+ X2 = wKey[130] ^ (int)Pack.BE_To_UInt32(input[4..]);
+ X1 = wKey[129] ^ (int)Pack.BE_To_UInt32(input[8..]);
+ X0 = wKey[128] ^ (int)Pack.BE_To_UInt32(input[12..]);
+
+ Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+ X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35];
+ InverseLT(); Ib7(X0, X1, X2, X3);
+ X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31];
+ InverseLT(); Ib6(X0, X1, X2, X3);
+ X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27];
+ InverseLT(); Ib5(X0, X1, X2, X3);
+ X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23];
+ InverseLT(); Ib4(X0, X1, X2, X3);
+ X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19];
+ InverseLT(); Ib3(X0, X1, X2, X3);
+ X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15];
+ InverseLT(); Ib2(X0, X1, X2, X3);
+ X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11];
+ InverseLT(); Ib1(X0, X1, X2, X3);
+ X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7];
+ InverseLT(); Ib0(X0, X1, X2, X3);
+
+ Pack.UInt32_To_BE((uint)(X3 ^ wKey[3]), output);
+ Pack.UInt32_To_BE((uint)(X2 ^ wKey[2]), output[4..]);
+ Pack.UInt32_To_BE((uint)(X1 ^ wKey[1]), output[8..]);
+ Pack.UInt32_To_BE((uint)(X0 ^ wKey[0]), output[12..]);
+ }
+#else
protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff)
{
X3 = (int)Pack.BE_To_UInt32(input, inOff);
@@ -211,14 +327,6 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_BE((uint)(wKey[128] ^ X0), output, outOff + 12);
}
- /**
- * Decrypt one block of ciphertext.
- *
- * @param input the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param output the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- */
protected override void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff)
{
X3 = wKey[131] ^ (int)Pack.BE_To_UInt32(input, inOff);
@@ -295,5 +403,6 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_BE((uint)(X1 ^ wKey[1]), output, outOff + 8);
Pack.UInt32_To_BE((uint)(X0 ^ wKey[0]), output, outOff + 12);
}
+#endif
}
}
diff --git a/crypto/src/crypto/engines/TwofishEngine.cs b/crypto/src/crypto/engines/TwofishEngine.cs
index 0758451e4..cb3e35b0a 100644
--- a/crypto/src/crypto/engines/TwofishEngine.cs
+++ b/crypto/src/crypto/engines/TwofishEngine.cs
@@ -299,11 +299,7 @@ namespace Org.BouncyCastle.Crypto.Engines
get { return false; }
}
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
throw new InvalidOperationException("Twofish not initialised");
@@ -311,6 +307,16 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ if (encrypting)
+ {
+ EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+ else
+ {
+ DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+ }
+#else
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
@@ -319,9 +325,32 @@ namespace Org.BouncyCastle.Crypto.Engines
{
DecryptBlock(input, inOff, output, outOff);
}
+#endif
+
+ return BLOCK_SIZE;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Twofish not initialised");
+
+ Check.DataLength(input, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, output);
+ }
+ else
+ {
+ DecryptBlock(input, output);
+ }
return BLOCK_SIZE;
}
+#endif
public void Reset()
{
@@ -424,6 +453,80 @@ namespace Org.BouncyCastle.Crypto.Engines
*/
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /**
+ * Encrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ *
+ * encryptBlock uses the pre-calculated gSBox[] and subKey[]
+ * arrays.
+ */
+ private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int x0 = (int)Pack.LE_To_UInt32(input) ^ gSubKeys[INPUT_WHITEN];
+ int x1 = (int)Pack.LE_To_UInt32(input[4..]) ^ gSubKeys[INPUT_WHITEN + 1];
+ int x2 = (int)Pack.LE_To_UInt32(input[8..]) ^ gSubKeys[INPUT_WHITEN + 2];
+ int x3 = (int)Pack.LE_To_UInt32(input[12..]) ^ gSubKeys[INPUT_WHITEN + 3];
+
+ int k = ROUND_SUBKEYS;
+ int t0, t1;
+ for (int r = 0; r < ROUNDS; r +=2)
+ {
+ t0 = Fe32_0(x0);
+ t1 = Fe32_3(x1);
+ x2 ^= t0 + t1 + gSubKeys[k++];
+ x2 = Integers.RotateRight(x2, 1);
+ x3 = Integers.RotateLeft(x3, 1) ^ (t0 + 2*t1 + gSubKeys[k++]);
+
+ t0 = Fe32_0(x2);
+ t1 = Fe32_3(x3);
+ x0 ^= t0 + t1 + gSubKeys[k++];
+ x0 = Integers.RotateRight(x0, 1);
+ x1 = Integers.RotateLeft(x1, 1) ^ (t0 + 2*t1 + gSubKeys[k++]);
+ }
+
+ Pack.UInt32_To_LE((uint)(x2 ^ gSubKeys[OUTPUT_WHITEN]), output);
+ Pack.UInt32_To_LE((uint)(x3 ^ gSubKeys[OUTPUT_WHITEN + 1]), output[4..]);
+ Pack.UInt32_To_LE((uint)(x0 ^ gSubKeys[OUTPUT_WHITEN + 2]), output[8..]);
+ Pack.UInt32_To_LE((uint)(x1 ^ gSubKeys[OUTPUT_WHITEN + 3]), output[12..]);
+ }
+
+ /**
+ * Decrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ */
+ private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int x2 = (int)Pack.LE_To_UInt32(input) ^ gSubKeys[OUTPUT_WHITEN];
+ int x3 = (int)Pack.LE_To_UInt32(input[4..]) ^ gSubKeys[OUTPUT_WHITEN + 1];
+ int x0 = (int)Pack.LE_To_UInt32(input[8..]) ^ gSubKeys[OUTPUT_WHITEN + 2];
+ int x1 = (int)Pack.LE_To_UInt32(input[12..]) ^ gSubKeys[OUTPUT_WHITEN + 3];
+
+ int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ;
+ int t0, t1;
+ for (int r = 0; r< ROUNDS ; r +=2)
+ {
+ t0 = Fe32_0(x2);
+ t1 = Fe32_3(x3);
+ x1 ^= t0 + 2*t1 + gSubKeys[k--];
+ x0 = Integers.RotateLeft(x0, 1) ^ (t0 + t1 + gSubKeys[k--]);
+ x1 = Integers.RotateRight(x1, 1);
+
+ t0 = Fe32_0(x0);
+ t1 = Fe32_3(x1);
+ x3 ^= t0 + 2*t1 + gSubKeys[k--];
+ x2 = Integers.RotateLeft(x2, 1) ^ (t0 + t1 + gSubKeys[k--]);
+ x3 = Integers.RotateRight(x3, 1);
+ }
+
+ Pack.UInt32_To_LE((uint)(x0 ^ gSubKeys[INPUT_WHITEN]), output);
+ Pack.UInt32_To_LE((uint)(x1 ^ gSubKeys[INPUT_WHITEN + 1]), output[4..]);
+ Pack.UInt32_To_LE((uint)(x2 ^ gSubKeys[INPUT_WHITEN + 2]), output[8..]);
+ Pack.UInt32_To_LE((uint)(x3 ^ gSubKeys[INPUT_WHITEN + 3]), output[12..]);
+ }
+#else
/**
* Encrypt the given input starting at the given offset and place
* the result in the provided buffer starting at the given offset.
@@ -432,11 +535,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* encryptBlock uses the pre-calculated gSBox[] and subKey[]
* arrays.
*/
- private void EncryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+ private void EncryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
int x0 = (int)Pack.LE_To_UInt32(src, srcIndex) ^ gSubKeys[INPUT_WHITEN];
int x1 = (int)Pack.LE_To_UInt32(src, srcIndex + 4) ^ gSubKeys[INPUT_WHITEN + 1];
@@ -471,11 +570,7 @@ namespace Org.BouncyCastle.Crypto.Engines
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*/
- private void DecryptBlock(
- byte[] src,
- int srcIndex,
- byte[] dst,
- int dstIndex)
+ private void DecryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
int x2 = (int)Pack.LE_To_UInt32(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN];
int x3 = (int)Pack.LE_To_UInt32(src, srcIndex + 4) ^ gSubKeys[OUTPUT_WHITEN + 1];
@@ -484,7 +579,7 @@ namespace Org.BouncyCastle.Crypto.Engines
int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ;
int t0, t1;
- for (int r = 0; r< ROUNDS ; r +=2)
+ for (int r = 0; r < ROUNDS ; r += 2)
{
t0 = Fe32_0(x2);
t1 = Fe32_3(x3);
@@ -504,6 +599,7 @@ namespace Org.BouncyCastle.Crypto.Engines
Pack.UInt32_To_LE((uint)(x2 ^ gSubKeys[INPUT_WHITEN + 2]), dst, dstIndex + 8);
Pack.UInt32_To_LE((uint)(x3 ^ gSubKeys[INPUT_WHITEN + 3]), dst, dstIndex + 12);
}
+#endif
/*
* TODO: This can be optimised and made cleaner by combining
diff --git a/crypto/src/crypto/engines/XTEAEngine.cs b/crypto/src/crypto/engines/XTEAEngine.cs
index 5fcfa4a57..e70498a5f 100644
--- a/crypto/src/crypto/engines/XTEAEngine.cs
+++ b/crypto/src/crypto/engines/XTEAEngine.cs
@@ -76,11 +76,7 @@ namespace Org.BouncyCastle.Crypto.Engines
setKey(p.GetKey());
}
- public virtual int ProcessBlock(
- byte[] inBytes,
- int inOff,
- byte[] outBytes,
- int outOff)
+ public virtual int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
if (!_initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
@@ -88,12 +84,33 @@ namespace Org.BouncyCastle.Crypto.Engines
Check.DataLength(inBytes, inOff, block_size, "input buffer too short");
Check.OutputLength(outBytes, outOff, block_size, "output buffer too short");
- return _forEncryption
- ? encryptBlock(inBytes, inOff, outBytes, outOff)
- : decryptBlock(inBytes, inOff, outBytes, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return _forEncryption
+ ? EncryptBlock(inBytes.AsSpan(inOff), outBytes.AsSpan(outOff))
+ : DecryptBlock(inBytes.AsSpan(inOff), outBytes.AsSpan(outOff));
+#else
+ return _forEncryption
+ ? EncryptBlock(inBytes, inOff, outBytes, outOff)
+ : DecryptBlock(inBytes, inOff, outBytes, outOff);
+#endif
}
- public virtual void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, block_size, "input buffer too short");
+ Check.OutputLength(output, block_size, "output buffer too short");
+
+ return _forEncryption
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
+ }
+#endif
+
+ public virtual void Reset()
{
}
@@ -119,13 +136,45 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
- private int encryptBlock(
- byte[] inBytes,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
// Pack bytes into integers
+ uint v0 = Pack.BE_To_UInt32(input);
+ uint v1 = Pack.BE_To_UInt32(input[4..]);
+
+ for (int i = 0; i < rounds; i++)
+ {
+ v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ _sum0[i];
+ v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ _sum1[i];
+ }
+
+ Pack.UInt32_To_BE(v0, output);
+ Pack.UInt32_To_BE(v1, output[4..]);
+
+ return block_size;
+ }
+
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ // Pack bytes into integers
+ uint v0 = Pack.BE_To_UInt32(input);
+ uint v1 = Pack.BE_To_UInt32(input[4..]);
+
+ for (int i = rounds - 1; i >= 0; i--)
+ {
+ v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ _sum1[i];
+ v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ _sum0[i];
+ }
+
+ Pack.UInt32_To_BE(v0, output);
+ Pack.UInt32_To_BE(v1, output[4..]);
+
+ return block_size;
+ }
+#else
+ private int EncryptBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ {
uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
uint v1 = Pack.BE_To_UInt32(inBytes, inOff + 4);
@@ -141,11 +190,7 @@ namespace Org.BouncyCastle.Crypto.Engines
return block_size;
}
- private int decryptBlock(
- byte[] inBytes,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private int DecryptBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
{
// Pack bytes into integers
uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
@@ -162,5 +207,6 @@ namespace Org.BouncyCastle.Crypto.Engines
return block_size;
}
+#endif
}
}
diff --git a/crypto/src/crypto/macs/CfbBlockCipherMac.cs b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
index 364cf8499..e10bb438d 100644
--- a/crypto/src/crypto/macs/CfbBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
@@ -9,7 +9,7 @@ namespace Org.BouncyCastle.Crypto.Macs
/**
* implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
*/
- class MacCFBBlockCipher
+ internal class MacCfbBlockCipher
: IBlockCipher
{
private byte[] IV;
@@ -26,7 +26,7 @@ namespace Org.BouncyCastle.Crypto.Macs
* feedback mode.
* @param blockSize the block size in bits (note: a multiple of 8)
*/
- public MacCFBBlockCipher(
+ public MacCfbBlockCipher(
IBlockCipher cipher,
int bitBlockSize)
{
@@ -47,13 +47,10 @@ namespace Org.BouncyCastle.Crypto.Macs
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public void Init(bool forEncryption, ICipherParameters parameters)
{
- if (parameters is ParametersWithIV)
+ if (parameters is ParametersWithIV ivParam)
{
- ParametersWithIV ivParam = (ParametersWithIV)parameters;
byte[] iv = ivParam.GetIV();
if (iv.Length < IV.Length)
@@ -99,30 +96,10 @@ namespace Org.BouncyCastle.Crypto.Macs
return blockSize;
}
- /**
- * Process one block of input from the array in and write it to
- * the out array.
- *
- * @param in the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
- if ((inOff + blockSize) > input.Length)
- throw new DataLengthException("input buffer too short");
-
- if ((outOff + blockSize) > outBytes.Length)
- throw new DataLengthException("output buffer too short");
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
@@ -143,7 +120,33 @@ namespace Org.BouncyCastle.Crypto.Macs
return blockSize;
}
- /**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ cipher.ProcessBlock(cfbV, cfbOutV);
+
+ //
+ // XOR the cfbV with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ output[i] = (byte)(cfbOutV[i] ^ input[i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ output[..blockSize].CopyTo(cfbV.AsSpan(cfbV.Length - blockSize));
+
+ return blockSize;
+ }
+#endif
+
+ /**
* reset the chaining vector back to the IV and reset the underlying
* cipher.
*/
@@ -167,7 +170,7 @@ namespace Org.BouncyCastle.Crypto.Macs
private byte[] mac;
private byte[] Buffer;
private int bufOff;
- private MacCFBBlockCipher cipher;
+ private MacCfbBlockCipher cipher;
private IBlockCipherPadding padding;
private int macSize;
@@ -247,7 +250,7 @@ namespace Org.BouncyCastle.Crypto.Macs
mac = new byte[cipher.GetBlockSize()];
- this.cipher = new MacCFBBlockCipher(cipher, cfbBitSize);
+ this.cipher = new MacCfbBlockCipher(cipher, cfbBitSize);
this.padding = padding;
this.macSize = macSizeInBits / 8;
diff --git a/crypto/src/crypto/macs/DSTU7564Mac.cs b/crypto/src/crypto/macs/DSTU7564Mac.cs
index 36e86418a..fc905cc99 100644
--- a/crypto/src/crypto/macs/DSTU7564Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7564Mac.cs
@@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Crypto.Macs
public void BlockUpdate(byte[] input, int inOff, int len)
{
- Check.DataLength(input, inOff, len, "Input buffer too short");
+ Check.DataLength(input, inOff, len, "input buffer too short");
if (paddedKey == null)
throw new InvalidOperationException(AlgorithmName + " not initialised");
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Crypto.Macs
public int DoFinal(byte[] output, int outOff)
{
- Check.OutputLength(output, outOff, macSize, "Output buffer too short");
+ Check.OutputLength(output, outOff, macSize, "output buffer too short");
if (paddedKey == null)
throw new InvalidOperationException(AlgorithmName + " not initialised");
diff --git a/crypto/src/crypto/modes/CbcBlockCipher.cs b/crypto/src/crypto/modes/CbcBlockCipher.cs
index 9345fd8c2..eb89c81ee 100644
--- a/crypto/src/crypto/modes/CbcBlockCipher.cs
+++ b/crypto/src/crypto/modes/CbcBlockCipher.cs
@@ -59,15 +59,12 @@ namespace Org.BouncyCastle.Crypto.Modes
this.encrypting = forEncryption;
- if (parameters is ParametersWithIV)
+ if (parameters is ParametersWithIV ivParam)
{
- ParametersWithIV ivParam = (ParametersWithIV)parameters;
- byte[] iv = ivParam.GetIV();
+ byte[] iv = ivParam.GetIV();
if (iv.Length != blockSize)
- {
throw new ArgumentException("initialisation vector must be the same length as block size");
- }
Array.Copy(iv, 0, IV, 0, iv.Length);
@@ -112,29 +109,27 @@ namespace Org.BouncyCastle.Crypto.Modes
return cipher.GetBlockSize();
}
- /**
- * Process one block of input from the array in and write it to
- * the out array.
- *
- * @param in the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return encrypting
+ ? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
+ : DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ return encrypting
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- return (encrypting)
- ? EncryptBlock(input, inOff, output, outOff)
- : DecryptBlock(input, inOff, output, outOff);
+ return encrypting
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
}
+#endif
/**
* reset the chaining vector back to the IV and reset the underlying
@@ -148,33 +143,50 @@ namespace Org.BouncyCastle.Crypto.Modes
cipher.Reset();
}
- /**
- * Do the appropriate chaining step for CBC mode encryption.
- *
- * @param in the array containing the data to be encrypted.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the encrypted data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- private int EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ for (int i = 0; i < blockSize; i++)
+ {
+ cbcV[i] ^= input[i];
+ }
+
+ int length = cipher.ProcessBlock(cbcV, output);
+
+ output[..blockSize].CopyTo(cbcV);
+
+ return length;
+ }
+
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- if ((inOff + blockSize) > input.Length)
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ input[..blockSize].CopyTo(cbcNextV);
+
+ int length = cipher.ProcessBlock(input, output);
+
+ for (int i = 0; i < blockSize; i++)
{
- throw new DataLengthException("input buffer too short");
+ output[i] ^= cbcV[i];
}
- /*
- * XOR the cbcV and the input,
- * then encrypt the cbcV
- */
+ byte[] tmp = cbcV;
+ cbcV = cbcNextV;
+ cbcNextV = tmp;
+
+ return length;
+ }
+#else
+ private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
+ {
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
+
for (int i = 0; i < blockSize; i++)
{
cbcV[i] ^= input[inOff + i];
@@ -182,60 +194,31 @@ namespace Org.BouncyCastle.Crypto.Modes
int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
- /*
- * copy ciphertext to cbcV
- */
Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
return length;
}
- /**
- * Do the appropriate chaining step for CBC mode decryption.
- *
- * @param in the array containing the data to be decrypted.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the decrypted data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- private int DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
- if ((inOff + blockSize) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
Array.Copy(input, inOff, cbcNextV, 0, blockSize);
int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
- /*
- * XOR the cbcV and the output
- */
for (int i = 0; i < blockSize; i++)
{
outBytes[outOff + i] ^= cbcV[i];
}
- /*
- * swap the back up buffer into next position
- */
- byte[] tmp;
-
- tmp = cbcV;
+ byte[] tmp = cbcV;
cbcV = cbcNextV;
cbcNextV = tmp;
return length;
}
+#endif
}
-
}
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index abd7dbb8d..8f0acce52 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -134,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Modes
byte[] outBytes,
int outOff)
{
- Check.DataLength(inBytes, inOff, inLen, "Input buffer too short");
+ Check.DataLength(inBytes, inOff, inLen, "input buffer too short");
data.Write(inBytes, inOff, inLen);
diff --git a/crypto/src/crypto/modes/CfbBlockCipher.cs b/crypto/src/crypto/modes/CfbBlockCipher.cs
index ed0be407a..bcbffcfb6 100644
--- a/crypto/src/crypto/modes/CfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/CfbBlockCipher.cs
@@ -108,56 +108,76 @@ namespace Org.BouncyCastle.Crypto.Modes
return blockSize;
}
- /**
- * Process one block of input from the array in and write it to
- * the out array.
- *
- * @param in the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- return (encrypting)
- ? EncryptBlock(input, inOff, output, outOff)
- : DecryptBlock(input, inOff, output, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return encrypting
+ ? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
+ : DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ return encrypting
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+#endif
}
- /**
- * Do the appropriate processing for CFB mode encryption.
- *
- * @param in the array containing the data to be encrypted.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the encrypted data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- if ((inOff + blockSize) > input.Length)
+ return encrypting
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
+ }
+#endif
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ cipher.ProcessBlock(cfbV, cfbOutV);
+ //
+ // XOR the cfbV with the plaintext producing the ciphertext
+ //
+ for (int i = 0; i < blockSize; i++)
{
- throw new DataLengthException("input buffer too short");
+ output[i] = (byte)(cfbOutV[i] ^ input[i]);
}
- if ((outOff + blockSize) > outBytes.Length)
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ output[..blockSize].CopyTo(cfbV.AsSpan(cfbV.Length - blockSize));
+ return blockSize;
+ }
+
+ public int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ input[..blockSize].CopyTo(cfbV.AsSpan(cfbV.Length - blockSize));
+ //
+ // XOR the cfbV with the ciphertext producing the plaintext
+ //
+ for (int i = 0; i < blockSize; i++)
{
- throw new DataLengthException("output buffer too short");
+ output[i] = (byte)(cfbOutV[i] ^ input[i]);
}
+ return blockSize;
+ }
+#else
+ public int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
+ {
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
+
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
//
// XOR the cfbV with the plaintext producing the ciphertext
@@ -173,32 +193,12 @@ namespace Org.BouncyCastle.Crypto.Modes
Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
return blockSize;
}
- /**
- * Do the appropriate processing for CFB mode decryption.
- *
- * @param in the array containing the data to be decrypted.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the encrypted data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+
+ public int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
- if ((inOff + blockSize) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
- if ((outOff + blockSize) > outBytes.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
+
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
//
// change over the input block.
@@ -214,6 +214,8 @@ namespace Org.BouncyCastle.Crypto.Modes
}
return blockSize;
}
+#endif
+
/**
* reset the chaining vector back to the IV and reset the underlying
* cipher.
diff --git a/crypto/src/crypto/modes/GOFBBlockCipher.cs b/crypto/src/crypto/modes/GOFBBlockCipher.cs
index 436b58a1d..4c8576a58 100644
--- a/crypto/src/crypto/modes/GOFBBlockCipher.cs
+++ b/crypto/src/crypto/modes/GOFBBlockCipher.cs
@@ -1,7 +1,7 @@
using System;
-using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Modes
{
@@ -131,41 +131,17 @@ namespace Org.BouncyCastle.Crypto.Modes
return blockSize;
}
- /**
- * Process one block of input from the array in and write it to
- * the out array.
- *
- * @param in the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- if ((inOff + blockSize) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + blockSize) > output.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, blockSize, "output buffer too short");
if (firstStep)
{
firstStep = false;
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
- N3 = bytesToint(ofbOutV, 0);
- N4 = bytesToint(ofbOutV, 4);
+ N3 = (int)Pack.LE_To_UInt32(ofbOutV, 0);
+ N4 = (int)Pack.LE_To_UInt32(ofbOutV, 4);
}
N3 += C2;
N4 += C1;
@@ -176,8 +152,8 @@ namespace Org.BouncyCastle.Crypto.Modes
N4++;
}
}
- intTobytes(N3, ofbV, 0);
- intTobytes(N4, ofbV, 4);
+ Pack.UInt32_To_LE((uint)N3, ofbV, 0);
+ Pack.UInt32_To_LE((uint)N4, ofbV, 4);
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
@@ -199,6 +175,52 @@ namespace Org.BouncyCastle.Crypto.Modes
return blockSize;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ if (firstStep)
+ {
+ firstStep = false;
+ cipher.ProcessBlock(ofbV, ofbOutV);
+ N3 = (int)Pack.LE_To_UInt32(ofbOutV, 0);
+ N4 = (int)Pack.LE_To_UInt32(ofbOutV, 4);
+ }
+ N3 += C2;
+ N4 += C1;
+ if (N4 < C1) // addition is mod (2**32 - 1)
+ {
+ if (N4 > 0)
+ {
+ N4++;
+ }
+ }
+ Pack.UInt32_To_LE((uint)N3, ofbV, 0);
+ Pack.UInt32_To_LE((uint)N4, ofbV, 4);
+
+ cipher.ProcessBlock(ofbV, ofbOutV);
+
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ output[i] = (byte)(ofbOutV[i] ^ input[i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
+ Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
+
+ return blockSize;
+ }
+#endif
+
/**
* reset the feedback vector back to the IV and reset the underlying
* cipher.
@@ -209,26 +231,5 @@ namespace Org.BouncyCastle.Crypto.Modes
cipher.Reset();
}
-
- //array of bytes to type int
- private int bytesToint(
- byte[] inBytes,
- int inOff)
- {
- return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
- ((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
- }
-
- //int to array of bytes
- private void intTobytes(
- int num,
- byte[] outBytes,
- int outOff)
- {
- outBytes[outOff + 3] = (byte)(num >> 24);
- outBytes[outOff + 2] = (byte)(num >> 16);
- outBytes[outOff + 1] = (byte)(num >> 8);
- outBytes[outOff] = (byte)num;
- }
}
}
diff --git a/crypto/src/crypto/modes/GcmSivBlockCipher.cs b/crypto/src/crypto/modes/GcmSivBlockCipher.cs
index 5af3429f2..2ea8eef1d 100644
--- a/crypto/src/crypto/modes/GcmSivBlockCipher.cs
+++ b/crypto/src/crypto/modes/GcmSivBlockCipher.cs
@@ -472,8 +472,8 @@ namespace Org.BouncyCastle.Crypto.Modes
if (badLen || myLast > myBufLen)
{
throw pOutput
- ? new OutputLengthException("Output buffer too short.")
- : new DataLengthException("Input buffer too short.");
+ ? new OutputLengthException("output buffer too short.")
+ : new DataLengthException("input buffer too short.");
}
}
diff --git a/crypto/src/crypto/modes/KCtrBlockCipher.cs b/crypto/src/crypto/modes/KCtrBlockCipher.cs
index ff0249a6c..79b74f84c 100644
--- a/crypto/src/crypto/modes/KCtrBlockCipher.cs
+++ b/crypto/src/crypto/modes/KCtrBlockCipher.cs
@@ -118,25 +118,30 @@ namespace Org.BouncyCastle.Crypto.Modes
public void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
- if (outOff + len > output.Length)
- {
- throw new DataLengthException("Output buffer too short");
- }
-
- if (inOff + len > input.Length)
- {
- throw new DataLengthException("Input buffer too small");
- }
+ Check.DataLength(input, inOff, len, "input buffer too small");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
int inStart = inOff;
int inEnd = inOff + len;
int outStart = outOff;
- while (inStart<inEnd)
+ while (inStart < inEnd)
+ {
+ output[outStart++] = CalculateByte(input[inStart++]);
+ }
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.OutputLength(output, input.Length, "output buffer too short");
+
+ for (int i = 0; i < input.Length; ++i)
{
- output[outStart++] = CalculateByte(input[inStart++]);
+ output[i] = CalculateByte(input[i]);
}
}
+#endif
protected byte CalculateByte(byte b)
{
@@ -176,19 +181,27 @@ namespace Org.BouncyCastle.Crypto.Modes
*/
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- if (input.Length - inOff< GetBlockSize())
- {
- throw new DataLengthException("Input buffer too short");
- }
- if (output.Length - outOff< GetBlockSize())
- {
- throw new DataLengthException("Output buffer too short");
- }
+ int blockSize = GetBlockSize();
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+
+ ProcessBytes(input, inOff, blockSize, output, outOff);
+
+ return blockSize;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int blockSize = GetBlockSize();
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
- ProcessBytes(input, inOff, GetBlockSize(), output, outOff);
+ ProcessBytes(input[..blockSize], output);
- return GetBlockSize();
+ return blockSize;
}
+#endif
/**
* reset the chaining vector back to the IV and reset the underlying
diff --git a/crypto/src/crypto/modes/OfbBlockCipher.cs b/crypto/src/crypto/modes/OfbBlockCipher.cs
index a99f8c5d7..ac9b9a06c 100644
--- a/crypto/src/crypto/modes/OfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/OfbBlockCipher.cs
@@ -61,9 +61,8 @@ namespace Org.BouncyCastle.Crypto.Modes
bool forEncryption, //ignored by this OFB mode
ICipherParameters parameters)
{
- if (parameters is ParametersWithIV)
+ if (parameters is ParametersWithIV ivParam)
{
- ParametersWithIV ivParam = (ParametersWithIV)parameters;
byte[] iv = ivParam.GetIV();
if (iv.Length < IV.Length)
@@ -118,36 +117,38 @@ namespace Org.BouncyCastle.Crypto.Modes
return blockSize;
}
- /**
- * Process one block of input from the array in and write it to
- * the out array.
- *
- * @param in the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- if ((inOff + blockSize) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+
+ cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
- if ((outOff + blockSize) > output.Length)
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
{
- throw new DataLengthException("output buffer too short");
+ output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
}
- cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+ //
+ // change over the input block.
+ //
+ Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
+ Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ cipher.ProcessBlock(ofbV, ofbOutV);
//
// XOR the ofbV with the plaintext producing the cipher text (and
@@ -155,7 +156,7 @@ namespace Org.BouncyCastle.Crypto.Modes
//
for (int i = 0; i < blockSize; i++)
{
- output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
+ output[i] = (byte)(ofbOutV[i] ^ input[i]);
}
//
@@ -166,6 +167,7 @@ namespace Org.BouncyCastle.Crypto.Modes
return blockSize;
}
+#endif
/**
* reset the feedback vector back to the IV and reset the underlying
diff --git a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
index 038ca783d..45998248c 100644
--- a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
@@ -79,29 +79,29 @@ namespace Org.BouncyCastle.Crypto.Modes
return cipher.GetBlockSize();
}
- /**
- * Process one block of input from the array in and write it to
- * the out array.
- *
- * @param in the array containing the input data.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the output data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- public int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
- return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) : DecryptBlock(input, inOff, output, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return forEncryption
+ ? EncryptBlock(input.AsSpan(inOff), output.AsSpan(outOff))
+ : DecryptBlock(input.AsSpan(inOff), output.AsSpan(outOff));
+#else
+ return forEncryption
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+#endif
}
- /**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ return forEncryption
+ ? EncryptBlock(input, output)
+ : DecryptBlock(input, output);
+ }
+#endif
+
+ /**
* reset the chaining vector back to the IV and reset the underlying
* cipher.
*/
@@ -125,15 +125,12 @@ namespace Org.BouncyCastle.Crypto.Modes
* @exception ArgumentException if the parameters argument is
* inappropriate.
*/
- public void Init(
- bool forEncryption,
- ICipherParameters parameters)
+ public void Init(bool forEncryption, ICipherParameters parameters)
{
this.forEncryption = forEncryption;
- if (parameters is ParametersWithIV)
+ if (parameters is ParametersWithIV ivParam)
{
- ParametersWithIV ivParam = (ParametersWithIV)parameters;
byte[] iv = ivParam.GetIV();
if (iv.Length < IV.Length)
@@ -169,34 +166,132 @@ namespace Org.BouncyCastle.Crypto.Modes
return (byte)(FRE[blockOff] ^ data);
}
- /**
- * Do the appropriate processing for CFB IV mode encryption.
- *
- * @param in the array containing the data to be encrypted.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the encrypted data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- private int EncryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- if ((inOff + blockSize) > input.Length)
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ if (count > blockSize)
{
- throw new DataLengthException("input buffer too short");
+ FR[blockSize - 2] = output[0] = EncryptByte(input[0], blockSize - 2);
+ FR[blockSize - 1] = output[1] = EncryptByte(input[1], blockSize - 1);
+
+ cipher.ProcessBlock(FR, FRE);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ FR[n - 2] = output[n] = EncryptByte(input[n], n - 2);
+ }
}
+ else if (count == 0)
+ {
+ cipher.ProcessBlock(FR, FRE);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = output[n] = EncryptByte(input[n], n);
+ }
- if ((outOff + blockSize) > outBytes.Length)
+ count += blockSize;
+ }
+ else if (count == blockSize)
{
- throw new DataLengthException("output buffer too short");
+ cipher.ProcessBlock(FR, FRE);
+
+ output[0] = EncryptByte(input[0], 0);
+ output[1] = EncryptByte(input[1], 1);
+
+ //
+ // do reset
+ //
+ Array.Copy(FR, 2, FR, 0, blockSize - 2);
+ output[..2].CopyTo(FR.AsSpan(blockSize - 2));
+
+ cipher.ProcessBlock(FR, FRE);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ FR[n - 2] = output[n] = EncryptByte(input[n], n - 2);
+ }
+
+ count += blockSize;
}
+ return blockSize;
+ }
+
+ private int DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ Check.DataLength(input, blockSize, "input buffer too short");
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ if (count > blockSize)
+ {
+ byte inVal = input[0];
+ FR[blockSize - 2] = inVal;
+ output[0] = EncryptByte(inVal, blockSize - 2);
+
+ inVal = input[1];
+ FR[blockSize - 1] = inVal;
+ output[1] = EncryptByte(inVal, blockSize - 1);
+
+ cipher.ProcessBlock(FR, FRE);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ inVal = input[n];
+ FR[n - 2] = inVal;
+ output[n] = EncryptByte(inVal, n - 2);
+ }
+ }
+ else if (count == 0)
+ {
+ cipher.ProcessBlock(FR, FRE);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = input[n];
+ output[n] = EncryptByte(input[n], n);
+ }
+
+ count += blockSize;
+ }
+ else if (count == blockSize)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ byte inVal1 = input[0];
+ byte inVal2 = input[1];
+ output[0] = EncryptByte(inVal1, 0);
+ output[1] = EncryptByte(inVal2, 1);
+
+ Array.Copy(FR, 2, FR, 0, blockSize - 2);
+
+ FR[blockSize - 2] = inVal1;
+ FR[blockSize - 1] = inVal2;
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ byte inVal = input[n];
+ FR[n - 2] = inVal;
+ output[n] = EncryptByte(inVal, n - 2);
+ }
+
+ count += blockSize;
+ }
+
+ return blockSize;
+ }
+#else
+ private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
+ {
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
+
if (count > blockSize)
{
FR[blockSize - 2] = outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2);
@@ -246,33 +341,10 @@ namespace Org.BouncyCastle.Crypto.Modes
return blockSize;
}
- /**
- * Do the appropriate processing for CFB IV mode decryption.
- *
- * @param in the array containing the data to be decrypted.
- * @param inOff offset into the in array the data starts at.
- * @param out the array the encrypted data will be copied into.
- * @param outOff the offset into the out array the output will start at.
- * @exception DataLengthException if there isn't enough data in in, or
- * space in out.
- * @exception InvalidOperationException if the cipher isn't initialised.
- * @return the number of bytes processed and produced.
- */
- private int DecryptBlock(
- byte[] input,
- int inOff,
- byte[] outBytes,
- int outOff)
+ private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
- if ((inOff + blockSize) > input.Length)
- {
- throw new DataLengthException("input buffer too short");
- }
-
- if ((outOff + blockSize) > outBytes.Length)
- {
- throw new DataLengthException("output buffer too short");
- }
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, blockSize, "output buffer too short");
if (count > blockSize)
{
@@ -300,7 +372,7 @@ namespace Org.BouncyCastle.Crypto.Modes
for (int n = 0; n < blockSize; n++)
{
FR[n] = input[inOff + n];
- outBytes[n] = EncryptByte(input[inOff + n], n);
+ outBytes[outOff + n] = EncryptByte(input[inOff + n], n);
}
count += blockSize;
@@ -333,5 +405,6 @@ namespace Org.BouncyCastle.Crypto.Modes
return blockSize;
}
+#endif
}
}
diff --git a/crypto/src/crypto/modes/SicBlockCipher.cs b/crypto/src/crypto/modes/SicBlockCipher.cs
index 0bea4a455..431e2952c 100644
--- a/crypto/src/crypto/modes/SicBlockCipher.cs
+++ b/crypto/src/crypto/modes/SicBlockCipher.cs
@@ -85,11 +85,7 @@ namespace Org.BouncyCastle.Crypto.Modes
return cipher.GetBlockSize();
}
- public virtual int ProcessBlock(
- byte[] input,
- int inOff,
- byte[] output,
- int outOff)
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
cipher.ProcessBlock(counter, 0, counterOut, 0);
@@ -110,6 +106,29 @@ namespace Org.BouncyCastle.Crypto.Modes
return counter.Length;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ cipher.ProcessBlock(counter, 0, counterOut, 0);
+
+ //
+ // XOR the counterOut with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < counterOut.Length; i++)
+ {
+ output[i] = (byte)(counterOut[i] ^ input[i]);
+ }
+
+ // Increment the counter
+ int j = counter.Length;
+ while (--j >= 0 && ++counter[j] == 0)
+ {
+ }
+
+ return counter.Length;
+ }
+#endif
+
public virtual void Reset()
{
Arrays.Fill(counter, (byte)0);
|