741 lines
32 KiB
C#
741 lines
32 KiB
C#
using System;
|
|
|
|
using Org.BouncyCastle.Crypto.Parameters;
|
|
|
|
namespace Org.BouncyCastle.Crypto.Engines
|
|
{
|
|
/**
|
|
* an implementation of Rijndael, based on the documentation and reference implementation
|
|
* by Paulo Barreto, Vincent Rijmen, for v2.0 August '99.
|
|
* <p>
|
|
* Note: this implementation is based on information prior to readonly NIST publication.
|
|
* </p>
|
|
*/
|
|
public class RijndaelEngine
|
|
: IBlockCipher
|
|
{
|
|
private static readonly int MAXROUNDS = 14;
|
|
|
|
private static readonly int MAXKC = (256/4);
|
|
|
|
private static readonly byte[] Logtable = {
|
|
(byte)0, (byte)0, (byte)25, (byte)1, (byte)50, (byte)2, (byte)26, (byte)198,
|
|
(byte)75, (byte)199, (byte)27, (byte)104, (byte)51, (byte)238, (byte)223, (byte)3,
|
|
(byte)100, (byte)4, (byte)224, (byte)14, (byte)52, (byte)141, (byte)129, (byte)239,
|
|
(byte)76, (byte)113, (byte)8, (byte)200, (byte)248, (byte)105, (byte)28, (byte)193,
|
|
(byte)125, (byte)194, (byte)29, (byte)181, (byte)249, (byte)185, (byte)39, (byte)106,
|
|
(byte)77, (byte)228, (byte)166, (byte)114, (byte)154, (byte)201, (byte)9, (byte)120,
|
|
(byte)101, (byte)47, (byte)138, (byte)5, (byte)33, (byte)15, (byte)225, (byte)36,
|
|
(byte)18, (byte)240, (byte)130, (byte)69, (byte)53, (byte)147, (byte)218, (byte)142,
|
|
(byte)150, (byte)143, (byte)219, (byte)189, (byte)54, (byte)208, (byte)206, (byte)148,
|
|
(byte)19, (byte)92, (byte)210, (byte)241, (byte)64, (byte)70, (byte)131, (byte)56,
|
|
(byte)102, (byte)221, (byte)253, (byte)48, (byte)191, (byte)6, (byte)139, (byte)98,
|
|
(byte)179, (byte)37, (byte)226, (byte)152, (byte)34, (byte)136, (byte)145, (byte)16,
|
|
(byte)126, (byte)110, (byte)72, (byte)195, (byte)163, (byte)182, (byte)30, (byte)66,
|
|
(byte)58, (byte)107, (byte)40, (byte)84, (byte)250, (byte)133, (byte)61, (byte)186,
|
|
(byte)43, (byte)121, (byte)10, (byte)21, (byte)155, (byte)159, (byte)94, (byte)202,
|
|
(byte)78, (byte)212, (byte)172, (byte)229, (byte)243, (byte)115, (byte)167, (byte)87,
|
|
(byte)175, (byte)88, (byte)168, (byte)80, (byte)244, (byte)234, (byte)214, (byte)116,
|
|
(byte)79, (byte)174, (byte)233, (byte)213, (byte)231, (byte)230, (byte)173, (byte)232,
|
|
(byte)44, (byte)215, (byte)117, (byte)122, (byte)235, (byte)22, (byte)11, (byte)245,
|
|
(byte)89, (byte)203, (byte)95, (byte)176, (byte)156, (byte)169, (byte)81, (byte)160,
|
|
(byte)127, (byte)12, (byte)246, (byte)111, (byte)23, (byte)196, (byte)73, (byte)236,
|
|
(byte)216, (byte)67, (byte)31, (byte)45, (byte)164, (byte)118, (byte)123, (byte)183,
|
|
(byte)204, (byte)187, (byte)62, (byte)90, (byte)251, (byte)96, (byte)177, (byte)134,
|
|
(byte)59, (byte)82, (byte)161, (byte)108, (byte)170, (byte)85, (byte)41, (byte)157,
|
|
(byte)151, (byte)178, (byte)135, (byte)144, (byte)97, (byte)190, (byte)220, (byte)252,
|
|
(byte)188, (byte)149, (byte)207, (byte)205, (byte)55, (byte)63, (byte)91, (byte)209,
|
|
(byte)83, (byte)57, (byte)132, (byte)60, (byte)65, (byte)162, (byte)109, (byte)71,
|
|
(byte)20, (byte)42, (byte)158, (byte)93, (byte)86, (byte)242, (byte)211, (byte)171,
|
|
(byte)68, (byte)17, (byte)146, (byte)217, (byte)35, (byte)32, (byte)46, (byte)137,
|
|
(byte)180, (byte)124, (byte)184, (byte)38, (byte)119, (byte)153, (byte)227, (byte)165,
|
|
(byte)103, (byte)74, (byte)237, (byte)222, (byte)197, (byte)49, (byte)254, (byte)24,
|
|
(byte)13, (byte)99, (byte)140, (byte)128, (byte)192, (byte)247, (byte)112, (byte)7
|
|
};
|
|
|
|
private static readonly byte[] Alogtable = {
|
|
(byte)0, (byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53,
|
|
(byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170,
|
|
(byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49,
|
|
(byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205,
|
|
(byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136,
|
|
(byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154,
|
|
(byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163,
|
|
(byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160,
|
|
(byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65,
|
|
(byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117,
|
|
(byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128,
|
|
(byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84,
|
|
(byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202,
|
|
(byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14,
|
|
(byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23,
|
|
(byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1,
|
|
(byte)3, (byte)5, (byte)15, (byte)17, (byte)51, (byte)85, (byte)255, (byte)26, (byte)46, (byte)114, (byte)150, (byte)161, (byte)248, (byte)19, (byte)53,
|
|
(byte)95, (byte)225, (byte)56, (byte)72, (byte)216, (byte)115, (byte)149, (byte)164, (byte)247, (byte)2, (byte)6, (byte)10, (byte)30, (byte)34, (byte)102, (byte)170,
|
|
(byte)229, (byte)52, (byte)92, (byte)228, (byte)55, (byte)89, (byte)235, (byte)38, (byte)106, (byte)190, (byte)217, (byte)112, (byte)144, (byte)171, (byte)230, (byte)49,
|
|
(byte)83, (byte)245, (byte)4, (byte)12, (byte)20, (byte)60, (byte)68, (byte)204, (byte)79, (byte)209, (byte)104, (byte)184, (byte)211, (byte)110, (byte)178, (byte)205,
|
|
(byte)76, (byte)212, (byte)103, (byte)169, (byte)224, (byte)59, (byte)77, (byte)215, (byte)98, (byte)166, (byte)241, (byte)8, (byte)24, (byte)40, (byte)120, (byte)136,
|
|
(byte)131, (byte)158, (byte)185, (byte)208, (byte)107, (byte)189, (byte)220, (byte)127, (byte)129, (byte)152, (byte)179, (byte)206, (byte)73, (byte)219, (byte)118, (byte)154,
|
|
(byte)181, (byte)196, (byte)87, (byte)249, (byte)16, (byte)48, (byte)80, (byte)240, (byte)11, (byte)29, (byte)39, (byte)105, (byte)187, (byte)214, (byte)97, (byte)163,
|
|
(byte)254, (byte)25, (byte)43, (byte)125, (byte)135, (byte)146, (byte)173, (byte)236, (byte)47, (byte)113, (byte)147, (byte)174, (byte)233, (byte)32, (byte)96, (byte)160,
|
|
(byte)251, (byte)22, (byte)58, (byte)78, (byte)210, (byte)109, (byte)183, (byte)194, (byte)93, (byte)231, (byte)50, (byte)86, (byte)250, (byte)21, (byte)63, (byte)65,
|
|
(byte)195, (byte)94, (byte)226, (byte)61, (byte)71, (byte)201, (byte)64, (byte)192, (byte)91, (byte)237, (byte)44, (byte)116, (byte)156, (byte)191, (byte)218, (byte)117,
|
|
(byte)159, (byte)186, (byte)213, (byte)100, (byte)172, (byte)239, (byte)42, (byte)126, (byte)130, (byte)157, (byte)188, (byte)223, (byte)122, (byte)142, (byte)137, (byte)128,
|
|
(byte)155, (byte)182, (byte)193, (byte)88, (byte)232, (byte)35, (byte)101, (byte)175, (byte)234, (byte)37, (byte)111, (byte)177, (byte)200, (byte)67, (byte)197, (byte)84,
|
|
(byte)252, (byte)31, (byte)33, (byte)99, (byte)165, (byte)244, (byte)7, (byte)9, (byte)27, (byte)45, (byte)119, (byte)153, (byte)176, (byte)203, (byte)70, (byte)202,
|
|
(byte)69, (byte)207, (byte)74, (byte)222, (byte)121, (byte)139, (byte)134, (byte)145, (byte)168, (byte)227, (byte)62, (byte)66, (byte)198, (byte)81, (byte)243, (byte)14,
|
|
(byte)18, (byte)54, (byte)90, (byte)238, (byte)41, (byte)123, (byte)141, (byte)140, (byte)143, (byte)138, (byte)133, (byte)148, (byte)167, (byte)242, (byte)13, (byte)23,
|
|
(byte)57, (byte)75, (byte)221, (byte)124, (byte)132, (byte)151, (byte)162, (byte)253, (byte)28, (byte)36, (byte)108, (byte)180, (byte)199, (byte)82, (byte)246, (byte)1,
|
|
};
|
|
|
|
private static readonly byte[] S = {
|
|
(byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197, (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
|
|
(byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240, (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
|
|
(byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204, (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
|
|
(byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154, (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
|
|
(byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160, (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
|
|
(byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91, (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
|
|
(byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133, (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
|
|
(byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245, (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
|
|
(byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23, (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
|
|
(byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136, (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
|
|
(byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92, (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
|
|
(byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169, (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
|
|
(byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198, (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
|
|
(byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14, (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
|
|
(byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148, (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
|
|
(byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104, (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
|
|
};
|
|
|
|
private static readonly byte[] Si = {
|
|
(byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56, (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
|
|
(byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135, (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
|
|
(byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61, (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
|
|
(byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178, (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
|
|
(byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22, (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
|
|
(byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218, (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
|
|
(byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10, (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
|
|
(byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2, (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
|
|
(byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234, (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
|
|
(byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133, (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
|
|
(byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137, (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
|
|
(byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32, (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
|
|
(byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49, (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
|
|
(byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13, (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
|
|
(byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176, (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
|
|
(byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38, (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
|
|
};
|
|
|
|
private static readonly int[] rcon = {
|
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
|
|
|
|
static readonly byte[][] shifts0 = new byte [][]
|
|
{
|
|
new byte [] { 0, 8, 16, 24 },
|
|
new byte [] { 0, 8, 16, 24 },
|
|
new byte [] { 0, 8, 16, 24 },
|
|
new byte [] { 0, 8, 16, 32 },
|
|
new byte [] { 0, 8, 24, 32 }
|
|
};
|
|
|
|
static readonly byte[][] shifts1 =
|
|
{
|
|
new byte [] { 0, 24, 16, 8 },
|
|
new byte [] { 0, 32, 24, 16 },
|
|
new byte [] { 0, 40, 32, 24 },
|
|
new byte [] { 0, 48, 40, 24 },
|
|
new byte [] { 0, 56, 40, 32 }
|
|
};
|
|
|
|
/**
|
|
* multiply two elements of GF(2^m)
|
|
* needed for MixColumn and InvMixColumn
|
|
*/
|
|
private byte Mul0x2(
|
|
int b)
|
|
{
|
|
if (b != 0)
|
|
{
|
|
return Alogtable[25 + (Logtable[b] & 0xff)];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private byte Mul0x3(
|
|
int b)
|
|
{
|
|
if (b != 0)
|
|
{
|
|
return Alogtable[1 + (Logtable[b] & 0xff)];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private byte Mul0x9(
|
|
int b)
|
|
{
|
|
if (b >= 0)
|
|
{
|
|
return Alogtable[199 + b];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private byte Mul0xb(
|
|
int b)
|
|
{
|
|
if (b >= 0)
|
|
{
|
|
return Alogtable[104 + b];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private byte Mul0xd(
|
|
int b)
|
|
{
|
|
if (b >= 0)
|
|
{
|
|
return Alogtable[238 + b];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private byte Mul0xe(
|
|
int b)
|
|
{
|
|
if (b >= 0)
|
|
{
|
|
return Alogtable[223 + b];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* xor corresponding text input and round key input bytes
|
|
*/
|
|
private void KeyAddition(
|
|
long[] rk)
|
|
{
|
|
A0 ^= rk[0];
|
|
A1 ^= rk[1];
|
|
A2 ^= rk[2];
|
|
A3 ^= rk[3];
|
|
}
|
|
|
|
private long Shift(
|
|
long r,
|
|
int shift)
|
|
{
|
|
//return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK;
|
|
|
|
ulong temp = (ulong) r >> shift;
|
|
|
|
// NB: This corrects for Mono Bug #79087 (fixed in 1.1.17)
|
|
if (shift > 31)
|
|
{
|
|
temp &= 0xFFFFFFFFUL;
|
|
}
|
|
|
|
return ((long) temp | (r << (BC - shift))) & BC_MASK;
|
|
}
|
|
|
|
/**
|
|
* Row 0 remains unchanged
|
|
* The other three rows are shifted a variable amount
|
|
*/
|
|
private void ShiftRow(
|
|
byte[] shiftsSC)
|
|
{
|
|
A1 = Shift(A1, shiftsSC[1]);
|
|
A2 = Shift(A2, shiftsSC[2]);
|
|
A3 = Shift(A3, shiftsSC[3]);
|
|
}
|
|
|
|
private long ApplyS(
|
|
long r,
|
|
byte[] box)
|
|
{
|
|
long res = 0;
|
|
|
|
for (int j = 0; j < BC; j += 8)
|
|
{
|
|
res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Replace every byte of the input by the byte at that place
|
|
* in the nonlinear S-box
|
|
*/
|
|
private void Substitution(
|
|
byte[] box)
|
|
{
|
|
A0 = ApplyS(A0, box);
|
|
A1 = ApplyS(A1, box);
|
|
A2 = ApplyS(A2, box);
|
|
A3 = ApplyS(A3, box);
|
|
}
|
|
|
|
/**
|
|
* Mix the bytes of every column in a linear way
|
|
*/
|
|
private void MixColumn()
|
|
{
|
|
long r0, r1, r2, r3;
|
|
|
|
r0 = r1 = r2 = r3 = 0;
|
|
|
|
for (int j = 0; j < BC; j += 8)
|
|
{
|
|
int a0 = (int)((A0 >> j) & 0xff);
|
|
int a1 = (int)((A1 >> j) & 0xff);
|
|
int a2 = (int)((A2 >> j) & 0xff);
|
|
int a3 = (int)((A3 >> j) & 0xff);
|
|
|
|
r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j;
|
|
|
|
r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j;
|
|
|
|
r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j;
|
|
|
|
r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j;
|
|
}
|
|
|
|
A0 = r0;
|
|
A1 = r1;
|
|
A2 = r2;
|
|
A3 = r3;
|
|
}
|
|
|
|
/**
|
|
* Mix the bytes of every column in a linear way
|
|
* This is the opposite operation of Mixcolumn
|
|
*/
|
|
private void InvMixColumn()
|
|
{
|
|
long r0, r1, r2, r3;
|
|
|
|
r0 = r1 = r2 = r3 = 0;
|
|
for (int j = 0; j < BC; j += 8)
|
|
{
|
|
int a0 = (int)((A0 >> j) & 0xff);
|
|
int a1 = (int)((A1 >> j) & 0xff);
|
|
int a2 = (int)((A2 >> j) & 0xff);
|
|
int a3 = (int)((A3 >> j) & 0xff);
|
|
|
|
//
|
|
// pre-lookup the log table
|
|
//
|
|
a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1;
|
|
a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1;
|
|
a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1;
|
|
a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1;
|
|
|
|
r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j;
|
|
|
|
r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j;
|
|
|
|
r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j;
|
|
|
|
r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j;
|
|
}
|
|
|
|
A0 = r0;
|
|
A1 = r1;
|
|
A2 = r2;
|
|
A3 = r3;
|
|
}
|
|
|
|
/**
|
|
* Calculate the necessary round keys
|
|
* The number of calculations depends on keyBits and blockBits
|
|
*/
|
|
private long[][] GenerateWorkingKey(
|
|
byte[] key)
|
|
{
|
|
int KC;
|
|
int t, rconpointer = 0;
|
|
int keyBits = key.Length * 8;
|
|
byte[,] tk = new byte[4,MAXKC];
|
|
//long[,] W = new long[MAXROUNDS+1,4];
|
|
long[][] W = new long[MAXROUNDS+1][];
|
|
|
|
for (int i = 0; i < MAXROUNDS+1; i++) W[i] = new long[4];
|
|
|
|
switch (keyBits)
|
|
{
|
|
case 128:
|
|
KC = 4;
|
|
break;
|
|
case 160:
|
|
KC = 5;
|
|
break;
|
|
case 192:
|
|
KC = 6;
|
|
break;
|
|
case 224:
|
|
KC = 7;
|
|
break;
|
|
case 256:
|
|
KC = 8;
|
|
break;
|
|
default :
|
|
throw new ArgumentException("Key length not 128/160/192/224/256 bits.");
|
|
}
|
|
|
|
if (keyBits >= blockBits)
|
|
{
|
|
ROUNDS = KC + 6;
|
|
}
|
|
else
|
|
{
|
|
ROUNDS = (BC / 8) + 6;
|
|
}
|
|
|
|
//
|
|
// copy the key into the processing area
|
|
//
|
|
int index = 0;
|
|
|
|
for (int i = 0; i < key.Length; i++)
|
|
{
|
|
tk[i % 4,i / 4] = key[index++];
|
|
}
|
|
|
|
t = 0;
|
|
|
|
//
|
|
// copy values into round key array
|
|
//
|
|
for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
W[t / (BC / 8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % BC);
|
|
}
|
|
}
|
|
|
|
//
|
|
// while not enough round key material calculated
|
|
// calculate new values
|
|
//
|
|
while (t < (ROUNDS+1)*(BC/8))
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
tk[i,0] ^= S[tk[(i+1)%4,KC-1] & 0xff];
|
|
}
|
|
tk[0,0] ^= (byte) rcon[rconpointer++];
|
|
|
|
if (KC <= 6)
|
|
{
|
|
for (int j = 1; j < KC; j++)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
tk[i,j] ^= tk[i,j-1];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int j = 1; j < 4; j++)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
tk[i,j] ^= tk[i,j-1];
|
|
}
|
|
}
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
tk[i,4] ^= S[tk[i,3] & 0xff];
|
|
}
|
|
for (int j = 5; j < KC; j++)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
tk[i,j] ^= tk[i,j-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// copy values into round key array
|
|
//
|
|
for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
W[t / (BC/8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % (BC));
|
|
}
|
|
}
|
|
}
|
|
return W;
|
|
}
|
|
|
|
private int BC;
|
|
private long BC_MASK;
|
|
private int ROUNDS;
|
|
private int blockBits;
|
|
private long[][] workingKey;
|
|
private long A0, A1, A2, A3;
|
|
private bool forEncryption;
|
|
private byte[] shifts0SC;
|
|
private byte[] shifts1SC;
|
|
|
|
/**
|
|
* default constructor - 128 bit block size.
|
|
*/
|
|
public RijndaelEngine() : this(128) {}
|
|
|
|
/**
|
|
* basic constructor - set the cipher up for a given blocksize
|
|
*
|
|
* @param blocksize the blocksize in bits, must be 128, 192, or 256.
|
|
*/
|
|
public RijndaelEngine(
|
|
int blockBits)
|
|
{
|
|
switch (blockBits)
|
|
{
|
|
case 128:
|
|
BC = 32;
|
|
BC_MASK = 0xffffffffL;
|
|
shifts0SC = shifts0[0];
|
|
shifts1SC = shifts1[0];
|
|
break;
|
|
case 160:
|
|
BC = 40;
|
|
BC_MASK = 0xffffffffffL;
|
|
shifts0SC = shifts0[1];
|
|
shifts1SC = shifts1[1];
|
|
break;
|
|
case 192:
|
|
BC = 48;
|
|
BC_MASK = 0xffffffffffffL;
|
|
shifts0SC = shifts0[2];
|
|
shifts1SC = shifts1[2];
|
|
break;
|
|
case 224:
|
|
BC = 56;
|
|
BC_MASK = 0xffffffffffffffL;
|
|
shifts0SC = shifts0[3];
|
|
shifts1SC = shifts1[3];
|
|
break;
|
|
case 256:
|
|
BC = 64;
|
|
BC_MASK = unchecked( (long)0xffffffffffffffffL);
|
|
shifts0SC = shifts0[4];
|
|
shifts1SC = shifts1[4];
|
|
break;
|
|
default:
|
|
throw new ArgumentException("unknown blocksize to Rijndael");
|
|
}
|
|
|
|
this.blockBits = blockBits;
|
|
}
|
|
|
|
/**
|
|
* initialise a Rijndael cipher.
|
|
*
|
|
* @param forEncryption whether or not we are for encryption.
|
|
* @param parameters the parameters required to set up the cipher.
|
|
* @exception ArgumentException if the parameters argument is
|
|
* inappropriate.
|
|
*/
|
|
public void Init(
|
|
bool forEncryption,
|
|
ICipherParameters parameters)
|
|
{
|
|
if (typeof(KeyParameter).IsInstanceOfType(parameters))
|
|
{
|
|
workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey());
|
|
this.forEncryption = forEncryption;
|
|
return;
|
|
}
|
|
|
|
throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString());
|
|
}
|
|
|
|
public string AlgorithmName
|
|
{
|
|
get { return "Rijndael"; }
|
|
}
|
|
|
|
public bool IsPartialBlockOkay
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public int GetBlockSize()
|
|
{
|
|
return BC / 2;
|
|
}
|
|
|
|
public int ProcessBlock(
|
|
byte[] input,
|
|
int inOff,
|
|
byte[] output,
|
|
int outOff)
|
|
{
|
|
if (workingKey == null)
|
|
{
|
|
throw new InvalidOperationException("Rijndael engine not initialised");
|
|
}
|
|
|
|
if ((inOff + (BC / 2)) > input.Length)
|
|
{
|
|
throw new DataLengthException("input buffer too short");
|
|
}
|
|
|
|
if ((outOff + (BC / 2)) > output.Length)
|
|
{
|
|
throw new DataLengthException("output buffer too short");
|
|
}
|
|
|
|
UnPackBlock(input, inOff);
|
|
|
|
if (forEncryption)
|
|
{
|
|
EncryptBlock(workingKey);
|
|
}
|
|
else
|
|
{
|
|
DecryptBlock(workingKey);
|
|
}
|
|
|
|
PackBlock(output, outOff);
|
|
|
|
return BC / 2;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
}
|
|
|
|
private void UnPackBlock(
|
|
byte[] bytes,
|
|
int off)
|
|
{
|
|
int index = off;
|
|
|
|
A0 = (long)(bytes[index++] & 0xff);
|
|
A1 = (long)(bytes[index++] & 0xff);
|
|
A2 = (long)(bytes[index++] & 0xff);
|
|
A3 = (long)(bytes[index++] & 0xff);
|
|
|
|
for (int j = 8; j != BC; j += 8)
|
|
{
|
|
A0 |= (long)(bytes[index++] & 0xff) << j;
|
|
A1 |= (long)(bytes[index++] & 0xff) << j;
|
|
A2 |= (long)(bytes[index++] & 0xff) << j;
|
|
A3 |= (long)(bytes[index++] & 0xff) << j;
|
|
}
|
|
}
|
|
|
|
private void PackBlock(
|
|
byte[] bytes,
|
|
int off)
|
|
{
|
|
int index = off;
|
|
|
|
for (int j = 0; j != BC; j += 8)
|
|
{
|
|
bytes[index++] = (byte)(A0 >> j);
|
|
bytes[index++] = (byte)(A1 >> j);
|
|
bytes[index++] = (byte)(A2 >> j);
|
|
bytes[index++] = (byte)(A3 >> j);
|
|
}
|
|
}
|
|
|
|
private void EncryptBlock(
|
|
long[][] rk)
|
|
{
|
|
int r;
|
|
|
|
//
|
|
// begin with a key addition
|
|
//
|
|
KeyAddition(rk[0]);
|
|
|
|
//
|
|
// ROUNDS-1 ordinary rounds
|
|
//
|
|
for (r = 1; r < ROUNDS; r++)
|
|
{
|
|
Substitution(S);
|
|
ShiftRow(shifts0SC);
|
|
MixColumn();
|
|
KeyAddition(rk[r]);
|
|
}
|
|
|
|
//
|
|
// Last round is special: there is no MixColumn
|
|
//
|
|
Substitution(S);
|
|
ShiftRow(shifts0SC);
|
|
KeyAddition(rk[ROUNDS]);
|
|
}
|
|
|
|
private void DecryptBlock(
|
|
long[][] rk)
|
|
{
|
|
int r;
|
|
|
|
// To decrypt: apply the inverse operations of the encrypt routine,
|
|
// in opposite order
|
|
//
|
|
// (KeyAddition is an involution: it 's equal to its inverse)
|
|
// (the inverse of Substitution with table S is Substitution with the inverse table of S)
|
|
// (the inverse of Shiftrow is Shiftrow over a suitable distance)
|
|
//
|
|
|
|
// First the special round:
|
|
// without InvMixColumn
|
|
// with extra KeyAddition
|
|
//
|
|
KeyAddition(rk[ROUNDS]);
|
|
Substitution(Si);
|
|
ShiftRow(shifts1SC);
|
|
|
|
//
|
|
// ROUNDS-1 ordinary rounds
|
|
//
|
|
for (r = ROUNDS-1; r > 0; r--)
|
|
{
|
|
KeyAddition(rk[r]);
|
|
InvMixColumn();
|
|
Substitution(Si);
|
|
ShiftRow(shifts1SC);
|
|
}
|
|
|
|
//
|
|
// End with the extra key addition
|
|
//
|
|
KeyAddition(rk[0]);
|
|
}
|
|
}
|
|
|
|
}
|